西行妖下
给一棵树,每个点有一个权值,解封概率为f[i]/i!,fi为长度为i的排列错排方案数,问某路径解封点数期望。支持修改(+,*)
原权值为1,修改为正整数,答案保留1位小数
nq 8e4
solution
错排公式:
证明:考虑最后一个元素,它有n-1种合法位置,然后如果那个位置的数在i即为f[n-2],不在i即为f[n-1]
首先我们打出错排方案的比值,发现它似乎是收敛的
也就是i>10时 F[i]/i! 基本不变
于是我想到了--上帝造题七分钟2!!
如果权值>20就当成20,对最终影响不变了
如果修改次数小于20则暴力修改,否则不管他
不过这个奇怪的题似乎要留20位才不会被卡精,照理说10位够了
10位=20分。。。。。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define db double
#define maxn 80005
using namespace std;
int n,q,head[maxn],top[maxn],size[maxn],fa[maxn],dfn[maxn],dy[maxn],deep[maxn],son[maxn];
int t1,t2,a,b,tot,sc,li,ri,val;
char ch[10];
struct node{
int v,nex;
}e[maxn*2];
struct no{
int l,r,fl,x;
double v;
}tree[maxn*8];
db Val[21]={
0.00000000000000000000,
0.00000000000000000000,
0.50000000000000000000,
0.33333333333333331000,
0.37500000000000000000,
0.36666666666666664000,
0.36805555555555558000,
0.36785714285714288000,
0.36788194444444444000,
0.36787918871252206000,
0.36787946428571427000,
0.36787943923360589000,
0.36787944132128159000,
0.36787944116069116000,
0.36787944117216193000,
0.36787944117139720000,
0.36787944117144500000,
0.36787944117144217000,
0.36787944117144233000,
0.36787944117144233000,
0.36787944117144233000,
};
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs1(int k,int fath){
fa[k]=fath;deep[k]=deep[fath]+1;
int sz=0,gp=-1;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v==fath)continue;
top[e[i].v]=e[i].v;
dfs1(e[i].v,k);sz+=size[e[i].v];
if(gp==-1||size[e[i].v]>size[gp])gp=e[i].v;
}
size[k]=sz+1;son[k]=gp;
}
void dfs2(int k){
dfn[k]=++sc;dy[sc]=k;
if(son[k]!=-1){
top[son[k]]=top[k];dfs2(son[k]);
}
for(int i=head[k];i;i=e[i].nex){
if(e[i].v==fa[k]||e[i].v==son[k])continue;
dfs2(e[i].v);
}
}
void wh(int k){
tree[k].v=tree[k*2].v+tree[k*2+1].v;
tree[k].x=tree[k*2].x+tree[k*2+1].x;//not true
tree[k].fl=(tree[k*2].fl&tree[k*2+1].fl);
}
void build(int k,int L,int R){
tree[k].l=L;tree[k].r=R;
if(L==R){
tree[k].x=1;tree[k].v=0;return;
}
int mid=L+R>>1;
build(k*2,L,mid);build(k*2+1,mid+1,R);
wh(k);
}
void Add(int k){
if(tree[k].fl)return;
if(tree[k].l==tree[k].r){
tree[k].x+=val;
if(tree[k].x>=20)tree[k].x=20,tree[k].fl=1;
tree[k].v=Val[tree[k].x];
return;
}
int mid=tree[k].l+tree[k].r>>1;
if(li<=mid)Add(k*2);if(ri>mid)Add(k*2+1);
wh(k);
}
void Mu(int k){
if(tree[k].fl)return;
if(tree[k].l==tree[k].r){
tree[k].x*=val;
if(tree[k].x>=20)tree[k].x=20,tree[k].fl=1;
tree[k].v=Val[tree[k].x];
return;
}
int mid=tree[k].l+tree[k].r>>1;
if(li<=mid)Mu(k*2);if(ri>mid)Mu(k*2+1);
wh(k);
}
db Q(int k){
if(tree[k].l>=li&&tree[k].r<=ri){
return tree[k].v;
}
int mid=(tree[k].l+tree[k].r)>>1;
db tmp=0;
if(li<=mid)tmp+=Q(k*2);if(ri>mid)tmp+=Q(k*2+1);
return tmp;
}
int main()
{
cin>>n;
for(int i=1;i<n;i++){
scanf("%d%d",&t1,&t2);
lj(t1,t2);lj(t2,t1);
}
dfs1(1,0);top[1]=1;dfs2(1);
build(1,1,sc);
cin>>q;
for(int i=1;i<=q;i++){
scanf(" %s",ch);
if(ch[0]=='A'){
scanf("%d%d%d",&a,&b,&val);
t1=top[a],t2=top[b];
while(t1!=t2){
if(deep[t1]<deep[t2])swap(t1,t2),swap(a,b);
li=dfn[t1],ri=dfn[a];
Add(1);
a=fa[t1];t1=top[a];
}
if(deep[a]<deep[b])swap(a,b);
li=dfn[b],ri=dfn[a];
Add(1);
}
if(ch[0]=='M'){
scanf("%d%d%d",&a,&b,&val);
if(val==1)continue;
t1=top[a],t2=top[b];
while(t1!=t2){
if(deep[t1]<deep[t2])swap(t1,t2),swap(a,b);
li=dfn[t1],ri=dfn[a];
Mu(1);
a=fa[t1];t1=top[a];
}
if(deep[a]<deep[b])swap(a,b);
li=dfn[b],ri=dfn[a];
Mu(1);
}
if(ch[0]=='Q'){
scanf("%d%d",&a,&b);
t1=top[a],t2=top[b];
db ans=0;
while(t1!=t2){
if(deep[t1]<deep[t2])swap(t1,t2),swap(a,b);
li=dfn[t1],ri=dfn[a];
ans+=Q(1);
a=fa[t1];t1=top[a];
}
if(deep[a]<deep[b])swap(a,b);
li=dfn[b],ri=dfn[a];
ans+=Q(1);
printf("%.1lf
",ans);
}
}
return 0;
}