P3781 [SDOI2017] 切树游戏

题意

给定一棵树,支持修改点权,查询导出子图满足权值为 \(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;
}
posted @ 2026-01-23 16:27  Uesugi1  阅读(0)  评论(0)    收藏  举报