[2020多校联考]MC

Solution

求概率。概率很好算,假设 \(X_i\) 所在连通块总生物数量为 \(S\),所有智商为 \(Y_i\) 的生物数为 \(s\)。那么概率就是

\[\binom{S}{N_i}\times\binom{s}{N_i}^{-1} \]

在模 \(19260817\) 意义下的值,后面的求一下逆元就可以了。
(注意:当 \(S\)\(s\) 其中之一小于 \(N_i\) 的话,概率为 \(0\)

那么这就转换为了一道计数题,显然是需要数据结构。维护连通块大小可以用并查集,维护连通块内某一种值的个数可以对每一个连通块维护一棵平衡树。对于操作一,直接在平衡树里加。对于操作二,因为并查集不支持分裂操作,按套路,可以倒着模拟这个过程,把分裂转为合并。只要首先预处理出删完边后的图和所有平衡树最后的情况,再倒过来处理询问。把操作一转换为减,操作二直接平衡树启发式合并,操作三直接查询即可。复杂度 \(O(n\log^2 n)\)

Tips

在平衡树内,对于相同 \(Y\) 值的点要合并成一个点,注意要把其中一个点的所有信息继承在另一个点上,否则会出现信息缺失的情况。在节点回收的时候要把其信息清空,之后才能用。
然后启发式合并判断大小时不要写反了
NOIP不知道能不能用 \(time.h\) 啊,反正今天模拟赛一发交上去RE了,好像是 \(time()\) 的问题。

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define N 200007
#define ll long long
#define Mod 19260817
#define lid ls[id]
#define rid rs[id]

inline int read(){
    int x=0,flag=1; char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
    return flag? x:-x;
}

ll qpow(ll x,ll y){
    ll ret=1,cnt=0;
    while(y>=(1LL<<cnt)){
        if(y&(1LL<<cnt)) ret=(ret*x)%Mod;
        x=(x*x)%Mod; cnt++;
    }
    return ret;
}

bool tag[N];
int n,m,Q,X[N],Y[N],fa[N];
int rt[N],key[N],sz[N],ls[N],rs[N],cnt=0,c[N];
ll s[N],S[N];

inline int find(int x){
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}

inline int New(int x,int y){
    key[++cnt]=rand();
    sz[cnt]=1;
    ls[cnt]=rs[cnt]=0;
    S[cnt]=s[cnt]=y,c[cnt]=x;
    return cnt;
}

inline void update(int id){
    sz[id]=sz[lid]+sz[rid]+1;
    S[id]=S[lid]+S[rid]+s[id];
}

void split(int id,int k,int &x,int &y){
    if(!id) x=y=0;
    else{    
        if(c[id]<=k) x=id,split(rid,k,rid,y);
        else y=id,split(lid,k,x,lid);
        update(id);
    }
}

int merge(int x,int y){
    if(!x||!y) return x+y;
    if(key[x]<key[y]){
        rs[x]=merge(rs[x],y);
        update(x); return x;
    }else{
        ls[y]=merge(x,ls[y]);
        update(y); return y;
    }
}

void uni(int &u,int v){
    if(ls[v]) uni(u,ls[v]);
    if(rs[v]) uni(u,rs[v]);
    int x,y,z;
    split(u,c[v],x,y);
    split(x,c[v]-1,x,z);
    ls[v]=rs[v]=0; sz[v]=1,S[v]=s[v];
    if(!z) u=merge(merge(x,v),y);
    else s[z]+=s[v],S[z]+=S[v],u=merge(merge(x,z),y);
}

void print(int id){
    if(lid) print(lid);
    printf("(%d,%lld) ",id,S[id]);
    if(rid) print(rid);
}

int ty[N],A[N],B[N],C[N],T[N];
ll ans[N],qp[N*10];
int main(){
    freopen("mc.in","r",stdin);
    freopen("mc.out","w",stdout);
    qp[0]=1;
    for(int i=1;i<N*10;i++)
        qp[i]=(qp[i-1]*i)%Mod;
    srand(19260817);
    n=read(),m=read(),Q=read();
    for(int i=1;i<=n;i++){
        int x=read(),y=read();
        rt[i]=New(y,x),fa[i]=i;
    }
    for(int i=1;i<=m;i++)
        X[i]=read(),Y[i]=read();
    for(int i=1;i<=Q;i++){
        ty[i]=read();
        if(ty[i]==2) T[i]=read(),tag[T[i]]=1;
        else{
            A[i]=read(),B[i]=read(),C[i]=read();
            if(ty[i]==1){
                int u=find(A[i]),x,y,z;
                split(rt[u],C[i],x,y);
                split(x,C[i]-1,x,z);
                if(!z) rt[u]=merge(merge(x,New(C[i],B[i])),y);
                else s[z]+=B[i],S[z]+=B[i],rt[u]=merge(merge(x,z),y);
            }
        }
    }
    for(int i=1;i<=m;i++){
        if(tag[i]) continue;
        int fa_x=find(X[i]),fa_y=find(Y[i]);
        if(fa_x==fa_y) continue;
        if(sz[fa_x]>sz[fa_y]) swap(fa_x,fa_y);
        uni(rt[fa_y],rt[fa_x]);
        fa[fa_x]=fa_y;
    }
    for(int i=Q;i;i--){
        if(ty[i]==1){
            int u=find(A[i]),x,y,z;
            split(rt[u],C[i],x,y);
            split(x,C[i]-1,x,z);
            s[z]-=B[i],S[z]-=B[i];
            rt[u]=merge(merge(x,z),y);
        }else if(ty[i]==2){
            int fa_x=find(X[T[i]]),fa_y=find(Y[T[i]]);
            if(fa_x==fa_y) continue;
            if(sz[fa_x]>sz[fa_y]) swap(fa_x,fa_y);
            uni(rt[fa_y],rt[fa_x]);
            fa[fa_x]=fa_y;
        }else{
            int u=find(A[i]),x,y,z;
            ll ret=S[rt[u]];
            split(rt[u],C[i],x,y);
            split(x,C[i]-1,x,z);
            if(c[z]==C[i]&&ret>=B[i]&&s[z]>=B[i])
                ans[i]=(qp[s[z]]*qp[ret-B[i]]%Mod)*qpow(qp[ret]*qp[s[z]-B[i]]%Mod,Mod-2)%Mod;
            else ans[i]=0;
            rt[u]=merge(merge(x,z),y);
        }
    }
    for(int i=1;i<=Q;i++)
        if(ty[i]==3) printf("%lld\n",ans[i]);
}
posted @ 2020-11-26 19:40  Kreap  阅读(98)  评论(1编辑  收藏  举报