[SDOI2017]切树游戏

题目

二轮毒瘤题啊

辣鸡洛谷竟然有卡树剖的数据

还是\(loj\)可爱

首先这道题没有带修,设\(dp_{i,j}\)表示以\(i\)为最高点的连通块有多少个异或和为\(j\)\(g_{i,j}=\sum_{k\in Tree(i)}dp_{k,j}\)\(k\in Tree(i)\)表示\(k\)\(i\)子树内部)

我们可以直接把每一个权值\(fwt\)一下,大力合并就好了,合并直接对位相乘,只需要在最后\(fwt\)回来就好了

但是我们有了修改,就变成了一道非常恶心的\(ddp\)

首先我们\(fwt\)肯定还是要\(fwt\)的,我们以下的\(dp\)都是\(fwt\)之后的

考虑我们的方程

\[dp_{i,j}=dp_{i,j}+dp_{i,j}\times dp_{v,j} \]

\[g_{i,j}=dp_{i,j}+g_{v,j} \]

我们考虑把重儿子和轻儿子分开处理,也就是\(ddp\)

\(f'\)表示没有处理重儿子的\(dp\)数组,\(g'\)表示没有处理重儿子的\(g\)数组

我们可以写成这样的矩阵

\[\begin{pmatrix} f_{son}\\ 1\\ g_{son} \end{pmatrix} \times \begin{pmatrix} f' & f' & 0 \\ 0 & 1 & 0 \\ f' & f'+g' & 1 \end{pmatrix}=\begin{pmatrix} f_{u}\\ 1\\ g_{u} \end{pmatrix} \]

猫老师的博客里提到这个矩阵只有一个地方是有用的,于是我们可以只存\(4\)个值来表示矩阵,从而大大优化常数

又因为我们\(fwt\)之后可以对于每一位单独考虑,于是我们直接来上\(128\)棵线段树分别维护每一位的值就好了

有一个问题就是我们需要撤回一个轻儿子的影响

设没有这个轻儿子的时候为\(f'\),轻儿子影响为\(v\)

则有

\[f=f'+f'\times v \]

则有

\[f'=\frac{f}{1+v} \]

但是如果\(1+v=0\),我们没有办法直接除掉这个影响

所以我们还需要对于每一个点维护出其有多少个轻儿子的会使得\(f\)变成\(0\),以及没有这些轻儿子的话\(f\)的值应该是多少

这样我们就能解决这个问题了

但是细节还是有一堆,非常非常难写

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=30005;
const int mod=10007;
const int Inv=5004;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt;}e[maxn<<1];
struct mat{int a,b,c,d;};
int n,num,len,m,Q,__;
int head[maxn],son[maxn],sum[maxn],deep[maxn],fa[maxn],top[maxn],S[128],H[128],inv[mod+5];
int bot[maxn],dp[maxn][128],g[maxn][128],dfn[maxn],id[maxn],pos[maxn],val[maxn][128];
int h[maxn][128],tmp[maxn][128],p[maxn][128];
int l[maxn*3],r[maxn*3];
inline void add(int x,int y) {
    e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
inline void Fwt(int *f,int o) {
    for(re int i=2;i<=len;i<<=1)
        for(re int ln=i>>1,l=0;l<len;l+=i)
            for(re int x=l;x<l+ln;++x) {
                int g=f[x],h=f[x+ln];
                f[x]=(g+h)%mod,f[x+ln]=(g-h+mod)%mod;
                if(o) f[x]=(f[x]*Inv)%mod,f[x+ln]=(f[x+ln]*Inv)%mod;
            }
}
void dfs1(int x) {
    sum[x]=1;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(deep[e[i].v]) continue;
        deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
        dfs1(e[i].v);sum[x]+=sum[e[i].v];
        if(sum[e[i].v]>=sum[son[x]]) son[x]=e[i].v;
    }
}
int dfs2(int x,int topf) {
    top[x]=topf,dfn[x]=++__,id[__]=x;
    if(son[x]) dfs2(son[x],topf);
        else return bot[x]=x;
    for(re int i=head[x];i;i=e[i].nxt)
    if(!top[e[i].v]) bot[e[i].v]=dfs2(e[i].v,e[i].v);
    return bot[x]=bot[son[x]];
}
inline mat operator*(mat a,mat b) {
    mat c;
    c.a=a.a*b.a%mod;
    c.b=(a.b+a.a*b.b%mod)%mod;
    c.c=(b.c+b.a*a.c%mod)%mod;
    c.d=(b.b*a.c%mod+a.d+b.d)%mod;
    return c;
}
struct Segment_Tree {
    mat d[maxn*3];
    inline void pushup(int i) {d[i]=d[i<<1]*d[i<<1|1];}
    mat query(int x,int y,int i) {
        if(x<=l[i]&&y>=r[i]) return d[i];
        int mid=l[i]+r[i]>>1;
        if(y<=mid) return query(x,y,i<<1);
        if(x>mid) return query(x,y,i<<1|1);
        return query(x,y,i<<1)*query(x,y,i<<1|1);
    }
    inline void change(int i,mat k) {
    	d[i]=k;i>>=1;
    	while(i) {d[i]=d[i<<1]*d[i<<1|1];i>>=1;}
    }
}t[128];
void build(int x,int y,int i) {
    l[i]=x,r[i]=y;
    if(x==y) {
        int k=id[x];pos[k]=i;
        for(re int o=head[k];o;o=e[o].nxt) 
        if(deep[e[o].v]>deep[k]&&son[k]!=e[o].v) 
            for(re int j=0;j<len;j++) {
            	dp[k][j]=(dp[k][j]+dp[k][j]*dp[e[o].v][j]%mod)%mod,
                g[k][j]=(g[k][j]+g[e[o].v][j])%mod,
                val[k][j]=(val[k][j]*(dp[e[o].v][j]+1))%mod;
                if((dp[e[o].v][j]+1)%mod!=0) h[k][j]=(h[k][j]*(dp[e[o].v][j]+1))%mod;
                	else tmp[k][j]++;
            }
        for(re int j=0;j<len;j++)
            t[j].d[i].a=t[j].d[i].b=t[j].d[i].c=dp[k][j],
            t[j].d[i].d=(g[k][j]+dp[k][j])%mod;
        if(son[k]) {
            for(re int j=0;j<len;j++)
                dp[k][j]=(dp[k][j]+dp[k][j]*dp[son[k]][j]%mod)%mod,
                g[k][j]=(g[k][j]+g[son[k]][j])%mod;
        }
        for(re int j=0;j<len;j++) g[k][j]=(g[k][j]+dp[k][j])%mod;
        return;
    }
    int mid=x+y>>1;
    build(mid+1,y,i<<1|1),build(x,mid,i<<1);
    for(re int j=0;j<len;j++) t[j].pushup(i);
}
signed main() {
    n=read(),len=read();
    for(re int x,i=1;i<=n;i++) {
        x=read();dp[i][x]++;Fwt(dp[i],0);
        for(re int j=0;j<len;j++) h[i][j]=val[i][j]=1,p[i][j]=dp[i][j];
    }
    inv[1]=1;
    for(re int i=2;i<mod;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for(re int x,y,i=1;i<n;i++) 
        x=read(),y=read(),add(x,y),add(y,x);
    deep[1]=1;dfs1(1);bot[1]=dfs2(1,1);
    build(1,n,1);char op[10];int x,v,X;
    Q=read();
    while(Q--) {
        scanf("%s",op);
        if(op[0]=='Q') {
            for(re int i=0;i<len;i++) {
                mat G=t[i].query(1,dfn[bot[1]],1);
                S[i]=G.d;
            }
            Fwt(S,1);
            x=read();printf("%d\n",S[x]);
        }else {
        	X=read(),v=read();
        	memset(H,0,sizeof(H));
        	H[v]++;Fwt(H,0);
        	for(re int i=0;i<len;i++) {
        		x=X;if(H[i]==p[x][i]) continue;
        		mat pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        		mat now=t[i].d[pos[x]];
        		now.a=H[i]*val[x][i]%mod;
        		now.d=(now.d-now.b+now.a+mod)%mod;
        		now.b=now.c=now.a;
        		t[i].change(pos[x],now);
        		if(top[x]==1) continue;
        		mat G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        		x=fa[top[x]];
        		while(1) {
        			now=t[i].d[pos[x]];
        			if(inv[pre.b+1]) {
        				now.a=now.a*inv[pre.b+1]%mod;
        				val[x][i]=(val[x][i]*inv[pre.b+1])%mod;
        				h[x][i]=(h[x][i]*inv[pre.b+1])%mod;
                    }
                    else {
                        tmp[x][i]--;
                        if(!tmp[x][i]) 
                            val[x][i]=h[x][i],now.a=(h[x][i]*p[x][i])%mod;
                    }
        			now.a=(now.a+now.a*G.b%mod)%mod;
        			now.d=(now.d-now.b+now.a+mod)%mod;
        			now.d=(now.d-pre.d+G.d+mod)%mod;
        			now.b=now.c=now.a;
        			val[x][i]=(val[x][i]*(G.b+1))%mod;
        			if((G.b+1)%mod==0) tmp[x][i]++;
        				else h[x][i]=(h[x][i]*(G.b+1))%mod;
        			pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        			t[i].change(pos[x],now);
        			if(top[x]==1) break;
        			G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        			x=fa[top[x]];
                }
            }
            for(re int i=0;i<len;i++) p[X][i]=H[i];
        }
    }
    return 0;
}

UPD

\(loj\)上发现了洛谷上卡树剖的数据的生成器,发现这个数据会反复操作同一个点

这不就好办了吗,我们开一个栈把修改存下来,每次遇到询问就弹栈,对于一个点只在其第一次出栈时修改

之后发现有一些取模没有必要,去掉之后就能卡过洛谷数据啦

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=30005;
const int mod=10007;
const int Inv=5004;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt;}e[maxn<<1];
struct mat{int a,b,c,d;};
int n,num,len,m,Q,__;
int head[maxn],son[maxn],sum[maxn],deep[maxn],fa[maxn],top[maxn],S[128],H[128],inv[mod+5];
int bot[maxn],dp[maxn][128],g[maxn][128],dfn[maxn],id[maxn],pos[maxn],val[maxn][128];
int h[maxn][128],tmp[maxn][128],p[maxn][128];
int l[maxn*3],r[maxn*3],a[maxn],b[maxn],Top,vis[maxn];
inline void add(int x,int y) {
    e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
inline void Fwt(int *f,int o) {
    for(re int i=2;i<=len;i<<=1)
        for(re int ln=i>>1,l=0;l<len;l+=i)
            for(re int x=l;x<l+ln;++x) {
                int g=f[x],h=f[x+ln];
                f[x]=(g+h)%mod,f[x+ln]=(g-h+mod)%mod;
                if(o) f[x]=(f[x]*Inv)%mod,f[x+ln]=(f[x+ln]*Inv)%mod;
            }
}
void dfs1(int x) {
    sum[x]=1;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(deep[e[i].v]) continue;
        deep[e[i].v]=deep[x]+1,fa[e[i].v]=x;
        dfs1(e[i].v);sum[x]+=sum[e[i].v];
        if(sum[e[i].v]>sum[son[x]]) son[x]=e[i].v;
    }
}
int dfs2(int x,int topf) {
    top[x]=topf,dfn[x]=++__,id[__]=x;
    if(son[x]) dfs2(son[x],topf);
        else return bot[x]=x;
    for(re int i=head[x];i;i=e[i].nxt)
    if(!top[e[i].v]) bot[e[i].v]=dfs2(e[i].v,e[i].v);
    return bot[x]=bot[son[x]];
}
inline mat operator*(mat a,mat b) {
    mat c;
    c.a=a.a*b.a%mod;
    c.b=(a.b+a.a*b.b)%mod;
    c.c=(b.c+b.a*a.c)%mod;
    c.d=(b.b*a.c%mod+a.d+b.d)%mod;
    return c;
}
struct Segment_Tree {
    mat d[maxn*3];
    inline void pushup(int i) {d[i]=d[i<<1]*d[i<<1|1];}
    mat query(const int x,const int y,re int i) {
        if(x<=l[i]&&y>=r[i]) return d[i];
        int mid=l[i]+r[i]>>1;
        if(y<=mid) return query(x,y,i<<1);
        if(x>mid) return query(x,y,i<<1|1);
        return query(x,y,i<<1)*query(x,y,i<<1|1);
    }
    inline void change(re int i,mat k) {
    	d[i]=k;i>>=1;
    	while(i) {pushup(i);i>>=1;}
    }
}t[128];
void build(int x,int y,int i) {
    l[i]=x,r[i]=y;
    if(x==y) {
        int k=id[x];pos[k]=i;
        for(re int o=head[k];o;o=e[o].nxt) 
        if(deep[e[o].v]>deep[k]&&son[k]!=e[o].v) 
            for(re int j=0;j<len;j++) {
            	dp[k][j]=(dp[k][j]+dp[k][j]*dp[e[o].v][j])%mod,
                g[k][j]=(g[k][j]+g[e[o].v][j])%mod,
                val[k][j]=(val[k][j]*(dp[e[o].v][j]+1))%mod;
                if((dp[e[o].v][j]+1)%mod!=0) h[k][j]=(h[k][j]*(dp[e[o].v][j]+1))%mod;
                	else tmp[k][j]++;
            }
        for(re int j=0;j<len;j++)
            t[j].d[i].a=t[j].d[i].b=t[j].d[i].c=dp[k][j],
            t[j].d[i].d=(g[k][j]+dp[k][j])%mod;
        if(son[k]) {
            for(re int j=0;j<len;j++)
                dp[k][j]=(dp[k][j]+dp[k][j]*dp[son[k]][j])%mod,
                g[k][j]=(g[k][j]+g[son[k]][j])%mod;
        }
        for(re int j=0;j<len;j++) g[k][j]=(g[k][j]+dp[k][j])%mod;
        return;
    }
    int mid=x+y>>1;
    build(mid+1,y,i<<1|1),build(x,mid,i<<1);
    for(re int j=0;j<len;j++) t[j].pushup(i);
}
inline void modify(int X,int v) {
    memset(H,0,sizeof(H));
    H[v]++;Fwt(H,0);int x;
    for(re int i=0;i<len;i++) {
        x=X;if(H[i]==p[x][i]) continue;
        mat pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        mat now=t[i].d[pos[x]];
        now.a=H[i]*val[x][i]%mod;
        now.d=(now.d-now.b+now.a+mod)%mod;
        now.b=now.c=now.a;
        t[i].change(pos[x],now);
        if(top[x]==1) continue;
        mat G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        x=fa[top[x]];
        while(1) {
        	now=t[i].d[pos[x]];
        	if(inv[pre.b+1]) {
        		now.a=now.a*inv[pre.b+1]%mod;
        		val[x][i]=(val[x][i]*inv[pre.b+1])%mod;
        		h[x][i]=(h[x][i]*inv[pre.b+1])%mod;
            }
            else {
                tmp[x][i]--;
                if(!tmp[x][i]) 
                        val[x][i]=h[x][i],now.a=(h[x][i]*p[x][i])%mod;
            }
        	now.a=(now.a+now.a*G.b)%mod;
        	now.d=(now.d-now.b+now.a+mod)%mod;
        	now.d=(now.d-pre.d+G.d+mod)%mod;
        	now.b=now.c=now.a;
        	val[x][i]=(val[x][i]*(G.b+1))%mod;
        	if((G.b+1)%mod==0) tmp[x][i]++;
        		else h[x][i]=(h[x][i]*(G.b+1))%mod;
        	pre=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        	t[i].change(pos[x],now);
        	if(top[x]==1) break;
        	G=t[i].query(dfn[top[x]],dfn[bot[x]],1);
        	x=fa[top[x]];
        }
    }
    for(re int i=0;i<len;i++) p[X][i]=H[i];
}
signed main() {
    n=read(),len=read();
    for(re int x,i=1;i<=n;i++) {
        x=read();dp[i][x]++;Fwt(dp[i],0);
        for(re int j=0;j<len;j++) h[i][j]=val[i][j]=1,p[i][j]=dp[i][j];
    }
    inv[1]=1;
    for(re int i=2;i<mod;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    for(re int x,y,i=1;i<n;i++) 
        x=read(),y=read(),add(x,y),add(y,x);
    deep[1]=1;dfs1(1);bot[1]=dfs2(1,1);
    build(1,n,1);char op[10];int x,v,X;
    Q=read();
    while(Q--) {
        scanf("%s",op);
        if(op[0]=='Q') {
        	int mid=Top;
        	while(Top) {
        		if(!vis[a[Top]]) modify(a[Top],b[Top]);
        		vis[a[Top]]=1;
                Top--; 
            }
            for(re int i=1;i<=mid;i++) vis[a[i]]=0;
            for(re int i=0;i<len;i++) {
                mat G=t[i].query(1,dfn[bot[1]],1);
                S[i]=G.d;
            }
            Fwt(S,1);
            x=read();printf("%d\n",S[x]);
        }else {
        	x=read(),v=read(),a[++Top]=x,b[Top]=v;
    	}
    }
    return 0;
}
posted @ 2019-04-12 20:09  asuldb  阅读(216)  评论(0编辑  收藏  举报