[ DP FWT 链分治 ] [ SDOI2017 ] BZOJ4911 切树游戏

9 篇文章 0 订阅
1 篇文章 0 订阅

题解

#include<bits/stdc++.h>
using namespace std;
char nc() {
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
void Read(int& x) {
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=(x<<3)+(x<<1)+c-48,c=nc());
}
void Read(char& c) {
    char C=nc();
    for(;C!='C'&&C!='Q';) C=nc();
    c=C;
}
const int N=30010;
const int M=128;
const int P=10007;
int inv[P];
struct Int {
    int a,b;
    Int(int a=0,int b=0):a(a),b(b){}
    void Set(int x) {
        if(x) a=x,b=0;else a=0,b=1;
    }
    void operator /= (int x) {
        if(x) a=a*inv[(x+P)%P]%P;else --b;
    }
    void operator *= (int x) {
        if(x) a=a*x%P;else ++b;
    }
    int Get() {
        return b?0:a;
    }
} g[N][M];
int k,n,m,x,y,q;
int h[N],t[N<<1],nx[N<<1],num;
int sz[N],f[N],d[N],top[N],son[N],sum[N],w[N];
int Rt[N],ls[N<<2],rs[N<<2],tot;
int c[N<<2][M],cl[N<<2][M],cr[N<<2][M],ca[N<<2][M];
int tmp[M][M];
int a[N],st[N];
int Ans[M];
char C;
void FWT(int* a,int n,int d) {
    for(int i=1;i<n;i<<=1)
        for(int j=0;j<n;j+=i<<1)
            for(int k=0;k<i;k++) {
                int x=a[j+k],y=a[j+k+i];
                if(d) a[j+k]=(x+y)%P,a[j+k+i]=(x-y)%P;else a[j+k]=(x+y)*inv[2]%P,a[j+k+i]=(x-y)*inv[2]%P;
            }
}
void Add(int x,int y) {
    t[++num]=y;nx[num]=h[x];h[x]=num;
}
void Dfs(int x,int y) {
    f[x]=y;d[x]=d[y]+1;sz[x]=1;
    for(int i=h[x];i;i=nx[i])
        if(t[i]!=y) {
            Dfs(t[i],x);
            sz[x]+=sz[t[i]];
            if(sz[t[i]]>sz[son[x]]) son[x]=t[i];
        }
}
void Up(int x) {
    for(int i=0;i<M;i++) {
        c[x][i]=(c[ls[x]][i]+c[rs[x]][i]+cr[ls[x]][i]*cl[rs[x]][i])%P;
        cl[x][i]=(cl[ls[x]][i]+ca[ls[x]][i]*cl[rs[x]][i])%P;
        cr[x][i]=(cr[rs[x]][i]+ca[rs[x]][i]*cr[ls[x]][i])%P;
        ca[x][i]=ca[ls[x]][i]*ca[rs[x]][i]%P;
    }
}
void Build(int& x,int l,int r) {
    x=++tot;
    if(l==r) {
        w[st[l]]=l;
        for(int i=0;i<M;i++) c[x][i]=cl[x][i]=cr[x][i]=ca[x][i]=g[st[l]][i].Get();
        return;
    }
    int Mid=l+r>>1;
    Build(ls[x],l,Mid);Build(rs[x],Mid+1,r);
    Up(x);
}
void Update(int x,int l,int r,int y,int z) {
    if(l==r) {
        for(int i=0;i<M;i++) c[x][i]=cl[x][i]=cr[x][i]=ca[x][i]=g[z][i].Get();
        return;
    }
    int Mid=l+r>>1;
    if(y<=Mid) Update(ls[x],l,Mid,y,z);else Update(rs[x],Mid+1,r,y,z);
    Up(x);
}
void Dfs1(int x,int y) {
    top[x]=y;
    for(int i=0;i<M;i++) g[x][i].Set(tmp[a[x]][i]);
    if(son[x]) Dfs1(son[x],y);
    for(int i=h[x];i;i=nx[i])
        if(t[i]!=f[x]&&t[i]!=son[x]) {
            Dfs1(t[i],t[i]);
            for(int j=0;j<M;j++) g[x][j]*=(cl[Rt[t[i]]][j]+tmp[0][j])%P;
        }
    if(x==y) {
        int cnt=0;
        for(int i=x;i;i=son[i]) st[++cnt]=i;
        Build(Rt[x],1,cnt);sum[x]=cnt;
        for(int i=0;i<M;i++) Ans[i]=(Ans[i]+c[Rt[x]][i])%P;
    }
}
void Modify(int x,int y) {
    if(a[x]==y) return;
    for(int i=0;i<M;i++) g[x][i]/=tmp[a[x]][i],g[x][i]*=tmp[y][i];
    a[x]=y;
    while(top[x]!=1) {
        int t=top[x];
        for(int i=0;i<M;i++) g[f[t]][i]/=(cl[Rt[t]][i]+tmp[0][i])%P,Ans[i]=(Ans[i]-c[Rt[t]][i])%P;
        Update(Rt[t],1,sum[t],w[x],x);
        for(int i=0;i<M;i++) g[f[t]][i]*=(cl[Rt[t]][i]+tmp[0][i])%P,Ans[i]=(Ans[i]+c[Rt[t]][i])%P;
        x=f[t];
    }
    for(int i=0;i<M;i++) Ans[i]=(Ans[i]-c[Rt[1]][i])%P;
    Update(Rt[1],1,sum[1],w[x],x);
    for(int i=0;i<M;i++) Ans[i]=(Ans[i]+c[Rt[1]][i])%P;
}
int main() {
    Read(n);Read(m);
    inv[0]=inv[1]=1;
    for(int i=2;i<P;i++) inv[i]=inv[P%i]*(P-P/i)%P;
    for(int i=1;i<=n;i++) Read(a[i]);
    for(int i=1;i<n;i++) Read(x),Read(y),Add(x,y),Add(y,x);
    for(int i=0;i<M;i++) tmp[i][i]=1,FWT(tmp[i],M,1);
    Dfs(1,0);Dfs1(1,1);
    Read(q);
    while(q--) {
        Read(C);
        if(C=='C') Read(x),Read(y),Modify(x,y);else {
            Read(x);
            FWT(Ans,M,0);
            printf("%d\n",(Ans[x]+P)%P);
            FWT(Ans,M,1);
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值