题意
给定一棵树,支持修改点权,查询导出子图满足权值为 \(x\) 的数量。权值定义为其中所有点权异或和,
设计状态 \(f_{u,x}\) 表示 \(u\) 为根的子树,权值为 \(x\) 的导出子图数量,容易写出转移方程:
\[f_{u,x}=f_{u,x}+\sum_{i\oplus j=x} f_{u,i}\cdot f_{v,j}
\]
发现这是一个子集卷积的形式,先对每个 \(f_u\) 的初始状态 FWT 一遍,卷积变为对位转移,最后再 IFWT 即可。
\[f_{u,x}=f_{u,x}+f_{u,x}\cdot f_{v,x}=(1+f_{v,x})f_{u,x}
\]
即:
\[f_{u,x}=f_{u,x}\prod_{v\in son(u)}(1+f_{v,x})
\]
维护 \(sum_{u,x}=\sum_{v\in sub(u)} f_{v,x}\),答案即为 \(sum_{1,x}\)。
没有修改的情况,可以 \(O(nm)\) 预处理,\(O(1)\) 查询。
单点修改考虑 DDP,重链剖分,维护转移需要的轻儿子信息,复杂度允许对每种权值都做一遍转移,对每种权值开单独的矩阵。
\[w_{u,x}=\prod_{v\in son(u)\wedge v\ne wson_u}(1+f_{v,x})\\
S_{u,x}=\sum_{v\in son(u)\wedge v\ne wson_u} sum_{v,x}
\]
先将从 \(wson_u\) 到 \(u\) 的 dp 转移写作矩阵形式。
\[\begin{bmatrix}
f_{wson_u,x}+1\\
sum_{wson_u,x}\\
1
\end{bmatrix}
\cdot
\begin{bmatrix}
w_u & 0 & 1\\
w_u & 1 & 1+S_{u,x}\\
0 & 0 & 1
\end{bmatrix}
=
\begin{bmatrix}
f_{u,x}+1\\
sum_{u,x}\\
1
\end{bmatrix}
\]
作为轻儿子时修改父节点的 \(w\),\(S\) 即可。跟 动态 dp(加强版) 基本相同。\(\log^2\) 过不去,用全局平衡二叉树维护即可做到 \(O(qmW\log n)\) 其中 \(W\) 是矩乘的复杂度。若被卡常可以展开矩乘会发现有几个位置的值是不变的,可以不维护。
还有就是模意义下 \(f_{wson_u,x}+1\) 为 0 时没有逆元无法退贡献,参考题解将每个数 0 因子分离表示为 \(x\cdot 0^y\) 这样乘除 0 改变指数即可,封装一下即可。
Takanashi Rikka
#include<bits/stdc++.h>
using namespace std;
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);o
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define il inline
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define ve vector
#define intz(x,y) memset((x),(y),sizeof((x)))
template<typename Type>il void cmx(Type &x,Type y){if(y>x)x=y;}
template<typename Type>il void cmn(Type &x,Type y){if(y<x)x=y;}
template<typename Type>
il typename Type::value_type MAX(Type f) {auto res=*f.begin();for(auto i=f.begin();i!=f.end();cmx(res,*i),i++);return res;
}
template<typename Type>
il typename Type::value_type MIN(Type f) {auto res=*f.begin();for(auto i=f.begin();i!=f.end();cmn(res,*i),i++);return res;
}
#define lowbit(x) (x&-x)
#define pcount(x) __builtin_popcountll(x)
const int N=3e4+5,mod=1e4+7,M=135;
ll qp(ll x,int y=mod-2){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
int ans[M],n,m,siz[N],son[N],F[N],p[N],sz[N],f[N][M],sum[N][M],a[N],S[N],s[N][2],tp[N],sf[N][M],cz[N][M],inv[mod+5],res[M][M];
struct NUM{int x,y;NUM(){x=1,y=0;}NUM operator*(int t){NUM res;res.x=x,res.y=y;t%=mod;if(t)res.x=t*res.x%mod;else ++res.y;return res;}NUM operator/(int t){NUM res;res.x=x,res.y=y;t%=mod;if(t)res.x=inv[t]*res.x%mod;else --res.y;return res;}int val(){return y>0?0:x;}
};
struct matrix{int w[3][3];matrix(){w[0][1]=w[0][2]=w[1][0]=w[1][2]=w[2][0]=w[2][1]=0;w[0][0]=w[1][1]=w[2][2]=1;}matrix operator*(const matrix x){matrix res;// res.w[0][0]=res.w[1][1]=res.w[2][2]=0;// for(int i=0;i<3;i++)// for(int j=0;j<3;j++)// for(int k=0;k<3;k++)// (res.w[i][j]+=w[k][j]*x.w[i][k]%mod)%=mod;res.w[0][0]=(1ll*w[0][0]*x.w[0][0]+1ll*w[1][0]*x.w[0][1]+1ll*w[2][0]*x.w[0][2])%mod,res.w[0][2]=(1ll*w[0][2]*x.w[0][0]+1ll*w[1][2]*x.w[0][1]+1ll*w[2][2]*x.w[0][2])%mod,res.w[1][0]=(1ll*w[0][0]*x.w[1][0]+1ll*w[1][0]*x.w[1][1]+1ll*w[2][0]*x.w[1][2])%mod,res.w[1][1]=(1ll*w[0][1]*x.w[1][0]+1ll*w[1][1]*x.w[1][1]+1ll*w[2][1]*x.w[1][2])%mod,res.w[1][2]=(1ll*w[0][2]*x.w[1][0]+1ll*w[1][2]*x.w[1][1]+1ll*w[2][2]*x.w[1][2])%mod,res.w[2][2]=(1ll*w[0][2]*x.w[2][0]+1ll*w[1][2]*x.w[2][1]+1ll*w[2][2]*x.w[2][2])%mod;return res;}void print(){for(int i=0;i<3;i++,cerr<<'\n')for(int j=0;j<3;j++)cerr<<w[i][j]<<' ';}
}V[N][M],t[N][M];
NUM w[N][M];
ve<int>e[N];
void FWT(int *f,int len,int fl){for(int i=2;i<=len;i<<=1)for(int j=0;j<len;j+=i)for(int k=0;k<(i>>1);k++){int x=f[j+k],y=f[j+k+(i>>1)];f[j+k]=(x+y)*fl%mod,f[j+k+(i>>1)]=(mod+(x-y)*fl%mod)%mod;}
}
void dfs(int u,int fa){siz[u]=1,F[u]=fa;for(int v:e[u])if(v^fa){dfs(v,u),siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;}sz[u]=siz[u]-siz[son[u]];
}
matrix get(int u,int i){matrix T;T.w[0][2]=1,T.w[0][0]=T.w[1][0]=w[u][i].val(),T.w[1][2]=sum[u][i];return T;
}
il void pushup(int u){for(int i=0;i<m;i++)t[u][i]=t[s[u][1]][i]*V[u][i]*t[s[u][0]][i];
}
int build(ve<int>&b,int L,int R,bool fl=0){if(!fl)for(int i=L;i<=R;i++)S[i]=S[i-1]+sz[b[i]];int l=L+1,r=R,mid;while(l<=r)(2*(S[mid=l+r>>1]-S[L-1])<=S[R]-S[L-1]?l=mid+1:r=mid-1);int rt=b[--l];if(L<l)s[rt][0]=build(b,L,l-1,1),p[s[rt][0]]=rt;if(R>l)s[rt][1]=build(b,l+1,R,1),p[s[rt][1]]=rt;pushup(rt);return rt;
}
int dfs1(int u){int x=u;ve<int>ls;ls.pb(0);do{for(int v:e[x])if((v^F[x])&&(v^son[x])){p[dfs1(v)]=x;for(int j=0;j<m;j++)(sf[x][j]+=sf[v][j])%=mod,w[x][j]=w[x][j]*(f[v][j]+1),(sum[x][j]+=sf[v][j])%=mod;}for(int j=0;j<m;j++)V[x][j]=get(x,j);tp[x]=u,ls.pb(x);}while(x=son[x]);int len=ls.size()-1;for(int i=len,u;i;i--){u=ls[i];for(int j=0;j<m;j++)f[u][j]=w[u][j].val()*(f[son[u]][j]+1)%mod,(sf[u][j]+=sf[son[u]][j]+f[u][j])%=mod;}return build(ls,1,len);
}
void del(int u){for(int x=u;p[x];x=p[x])if(s[p[x]][0]==x||s[p[x]][1]==x);else{for(int j=0;j<m;j++)w[p[x]][j]=w[p[x]][j]/(f[tp[x]][j]+1),(sum[p[x]][j]+=mod-sf[tp[x]][j])%=mod;}
}
void add(int u){pushup(u);for(int x=u;p[x];x=p[x]){if(s[p[x]][0]==x||s[p[x]][1]==x)pushup(p[x]);else{for(int j=0;j<m;j++){f[tp[x]][j]=(t[x][j].w[0][0]+t[x][j].w[0][2]+mod-1)%mod,sf[tp[x]][j]=(t[x][j].w[1][0]+t[x][j].w[1][2])%mod;w[p[x]][j]=w[p[x]][j]*(f[tp[x]][j]+1),(sum[p[x]][j]+=sf[tp[x]][j])%=mod;V[p[x]][j]=get(p[x],j);}pushup(p[x]);}}
}
void chg(int u,int x){del(u);for(int j=0;j<m;j++)w[u][j]=w[u][j]/res[a[u]][j],w[u][j]=w[u][j]*res[x][j],V[u][j]=get(u,j);a[u]=x;add(u);
}
void UesugiErii(){cin>>n>>m;for(int i=0;i<m;i++)res[i][i]=1,FWT(res[i],m,1);for(int i=1;i<=n;i++){cin>>a[i];for(int j=0;j<m;j++)w[i][j]=w[i][j]*res[a[i]][j];}for(int i=1,u,v;i<n;i++)cin>>u>>v,e[u].pb(v),e[v].pb(u);dfs(1,0),dfs1(1);int rt=1;while(p[rt])rt=p[rt];for(int i=0;i<m;i++)ans[i]=(t[rt][i].w[1][0]+t[rt][i].w[1][2])%mod;FWT(ans,m,inv[2]);int q;cin>>q;while(q--){string opt;int x,y;cin>>opt>>x;if(opt[0]=='C'){cin>>y,chg(x,y);for(int i=0;i<m;i++)ans[i]=(t[rt][i].w[1][0]+t[rt][i].w[1][2])%mod;FWT(ans,m,inv[2]);}else cout<<ans[x]<<'\n';}
}
signed main(){//IO();cfast;for(int i=0;i<=mod+1;i++)inv[i]=qp(i);int _=1;//cin>>_;for(;_;_--)UesugiErii();return 0;
}