DTOJ 4021 西行妖下

版权声明:神犇使用记得标明出处哦QAQ https://blog.csdn.net/qq_41717018/article/details/83622322

西行妖下
【题目背景】
埋骨于西行妖下,已经多少年了……
幽冥的公主,亡魂的哭泣……
“人间……应该有春吗?”
“反魂蝶,最高八分,最终也无法让西行妖绽放吗……”
【题目描述】
幽幽子站在西行妖下,她需要解封西行妖最后的力量。
西行妖可以当作一个有 n n 个点的树,每个点都有一些符文,初始每个点符文个数为 1 1
幽幽子可以施展魔法,将符文随机移动,来解封封印。
每个点上的符文可以看作是一个 1   m 1~m 的排列,原本的状态为 1 , 2 , 3 , 4 , , m 1,2,3,4,……,m 按顺序排列
( m m 为符文的个数)。想要解封一个点上的封印,要求排列中对于任意的 i i i p i i\ne p_{i} 。幽幽子
每次的魔法效果是随机形成一个排列,尝试能否解除封印。
幽幽子每次会走过一条路径,从s 到t,对每个点施展一次魔法,并询问能解封的点的
期望个数。
现在有 Q Q 次操作:
A d d Add s s t t x x s s t t 的路径上每个点加x 个新的符文。
M u l t i Multi s s t t x x s s t t 的路径上,每个点符文个数 × x \times x
Q u e r y Query s s t t 求从 s s t t 解封点的期望个数是多少。
(注意:每次 Q u e r y Query 操作是独立的,即前一次 Q u e r y Query 中施展的魔法在Query 结束时被立即撤销,所有走过的路径上点的符文排列变为 p i = i p_{i}=i ,对后续操作不产生影响)
【输入格式】
第一行一个数 n n ,表示树的点数。
下面 n 1 n-1 行,每行两个数 u u v v ,表示有一条边连接 u u v v
下面一行一个 Q Q ,表示操作次数。
下面 Q Q 行,每行一个操作:
A d d Add s s t t x x s s t t 的路径上每个点加x 个新的符文。
M u l t i Multi s s t t x x s s t t 的路径上,每个点符文个数 × x \times x
Q u e r y Query s s t t 求从 s s t t 解封点的期望个数是多少。
【输出格式】
对于每次询问 Q u e r y Query ,输出一行一个实数(为了避免卡精度,所以只需要保留 1 1 位小数),
表示解封点的期望个数。
【样例输入】
2
1 2
3
Query 1 2
Add 1 1 1
Query 1 2
【样例输出】
0.0
0.5

【数据范围】
n 80000 , Q 80000 n\leq 80000,Q\leq 80000

题解:

首先要知道,设 f i f_{i} 表示长度为 i i 的排列的错排方案,
证明及推导见大神博客
则每个点合法的概率是 f i i ! \frac{f_{i}}{i!}
通过严谨的证明(打表 ) 可得,当 i > = 20 i>=20 时,这个值会趋近相等。
于是对于每个点只需要加/乘到大于等于 20 20 就不用再改了。
然后直接树剖套线段树,由于每个点不会被改超过二十次(乘1特判掉)。
于是区间修改直接暴力化成单点。

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i--)
#define For(i,a,b) for(re int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
#define shenben puts("orzlkw");
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
typedef double db;
const db p[30]={
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,
};
const int N=80004;
int n;
struct E{
    int to,nxt;
}e[N<<1];
int head[N],tot;
in void ins(int x,int y){
    e[++tot]=E{y,head[x]},head[x]=tot;
}
int sz[N],top[N],dep[N],son[N],fa[N];
int pos[N],idx[N],id;
struct T_seg{
    struct seg{
        int l,r,mn,t1,t2,s;db sum;
    }t[N*4];
    in void build(int x,int l,int r){
        //cout<<x<<" "<<l<<" "<<r<<endl;
        t[x].l=l,t[x].r=r;
        //cout<<x<<' '<<t[x].l<<" "<<t[x].r<<endl;
        t[x].mn=1;
        if(l==r){return;} 
        int mid=l+r>>1;
        //cout<<mid<<endl;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    }
    in void upd(int x){
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
        t[x].mn=min(t[x<<1].mn,t[x<<1|1].mn);
    }
    in void mod(int x,int L,int R,int v,int op){
        //pushdown(x);
        if(t[x].mn>=20) return;
        //cout<<"#"<<t[x].l<<" "<<t[x].mn<<" "<<t[x].r<<endl;
        if(t[x].r<L||t[x].l>R) return;
        if(t[x].l==t[x].r){
            if(op==1){
                t[x].sum-=p[t[x].mn],t[x].mn=min(20,t[x].mn+v);
                t[x].sum+=p[t[x].mn];   
            } 
            else{
                t[x].sum-=p[t[x].mn],t[x].mn=min(20,t[x].mn*v);
                t[x].sum+=p[t[x].mn];
            }
            //cout<<t[x].mn<<endl;
            //cout<<x<<" "<<t[x].l<<" "<<t[x].r<<" "<<t[x].sum<<endl;
            return;
        }
        int mid=t[x].l+t[x].r>>1;
        mod(x<<1,L,R,v,op);
        mod(x<<1|1,L,R,v,op);
        upd(x);
    }
    in db Q(int x,int L,int R){
        //pushdown(x);
        if(t[x].l>=L&&t[x].r<=R) return t[x].sum;
        int mid=t[x].l+t[x].r>>1;db res=0;
        if(L<=mid) res+=Q(x<<1,L,R);
        if(mid<R) res+=Q(x<<1|1,L,R);
        return res;
    }
}t;
struct T_cut{
    in void dfs1(int x,int depth){
        dep[x]=depth;sz[x]=1;
        for(int i=head[x];i;i=e[i].nxt){
            if(e[i].to==fa[x]) continue;
            fa[e[i].to]=x;
            dfs1(e[i].to,depth+1);
            sz[x]+=sz[e[i].to];
            if(sz[son[x]]<sz[e[i].to]) son[x]=e[i].to;
        }
    }
    in void dfs2(int x,int chain){
        top[x]=chain;pos[x]=++id;idx[id]=x;
        if(son[x]) dfs2(son[x],chain);
        for(int i=head[x];i;i=e[i].nxt){
            if(e[i].to==fa[x]||e[i].to==son[x]) continue;
            dfs2(e[i].to,e[i].to);
        }
    }
    in void work(int x,int y,int v,int op){
        db ans=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            if(op==0) ans+=t.Q(1,pos[top[x]],pos[x]);
            if(op==1) t.mod(1,pos[top[x]],pos[x],v,1);
            if(op==2) t.mod(1,pos[top[x]],pos[x],v,2);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]) swap(x,y);
        if(op==0) ans+=t.Q(1,pos[x],pos[y]),printf("%.1lf\n",ans);
        if(op==1) t.mod(1,pos[x],pos[y],v,1);
        if(op==2) t.mod(1,pos[x],pos[y],v,2);
    }
}T;
char s[50];
int main(){
    g(n);
    For(i,1,n){
        int x,y;g(x),g(y);
        ins(x,y);ins(y,x);
    }
    T.dfs1(1,1),T.dfs2(1,1);
    t.build(1,1,n);
    int QQ;g(QQ);
    while(QQ--){
        scanf(" %s",s);int x,y;g(x),g(y);
        if(s[0]=='Q'){
            T.work(x,y,0,0);
        }
        if(s[0]=='A'){
            int z;g(z);
            T.work(x,y,z,1);
        }
        if(s[0]=='M'){
            int z;g(z);if(z==1) continue;
            T.work(x,y,z,2);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41717018/article/details/83622322