[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\)之后的
考虑我们的方程
我们考虑把重儿子和轻儿子分开处理,也就是\(ddp\)了
设\(f'\)表示没有处理重儿子的\(dp\)数组,\(g'\)表示没有处理重儿子的\(g\)数组
我们可以写成这样的矩阵
猫老师的博客里提到这个矩阵只有一个地方是有用的,于是我们可以只存\(4\)个值来表示矩阵,从而大大优化常数
又因为我们\(fwt\)之后可以对于每一位单独考虑,于是我们直接来上\(128\)棵线段树分别维护每一位的值就好了
有一个问题就是我们需要撤回一个轻儿子的影响
设没有这个轻儿子的时候为\(f'\),轻儿子影响为\(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;
}