西行妖下

西行妖下
給一棵樹,每個點有一個權值,解封概率爲f[i]/i!,fi爲長度爲i的排列錯排方案數,問某路徑解封點數期望。支持修改(+,*)

原權值爲1,修改爲正整數,答案保留1位小數

nq 8e4

 


solution

錯排公式:f[i]=(n-1)*(f[i-1]+f[i-2])

證明:考慮最後一個元素,它有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\n",ans);
        }
    }
    return 0;
}
 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章