[SDOI2017]切树游戏 (全局平衡二叉树维护动态DP)

基于变换合并的树上动态 DP 的链分治算法 & SDOI2017 切树游戏(cut)解题报告
切了一晚树心态崩了。
你问我怎么求异或逆卷积。
我,我。我???我!!!!!才不会说是把FWT后的数组每个求个逆元呢。。。。。。。
怎么模数为质数还有没有逆元的操作啊!!!!!

对于10007的倍数没有逆元的情况,标程的方法是维护非0部分的积和0的个数,这样就可减了
-Claris

不然就要打用数据结构维护轻儿子的( t o p − t r e e ? top-tree? toptree?)

AC Code:

#include
#define maxn 30005
#define maxm 128
#define mod 10007
using namespace std;

int n,m;
int inv[mod]={1,1};
int w[maxn],v[maxn][maxm],cg0[maxn][maxm],g[maxn][maxm],gu[maxn][maxm],val[maxm][maxm],ls[maxn][maxm],rs[maxn][maxm],su[maxn][maxm],sum[maxn][maxm];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e=0;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
void FWT(int *a,int tp){
	static int c[2] = {(mod+1)/2,1};
	for(int L=2;L<=m;L<<=1)
		for(int l=L>>1,st=0;st<m;st+=L)
			for(int k=st;k<st+l;k++)
			{
				int x = a[k] , y = a[k+l];
				a[k] = (x + y) * c[tp==1] % mod , 
				a[k+l] = (x-y) * c[tp==1] % mod;
			}
}

int siz[maxn],son[maxn],fa[maxn],ch[maxn][2],id[maxn],pos[maxn],tot,rt;

void dfs1(int now,int ff){
	siz[now] = 1 , son[now] = -1;
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff){
			dfs1(to[i],now);
			siz[now] += siz[to[i]];
			if(son[now] == -1 || siz[to[i]] > siz[son[now]])
				son[now] = to[i];
		}
}

void upd(int now){
	int lc = ch[now][0] , rc = ch[now][1];
	for(int i=0;i<m;i++)
	{
		sum[now][i] = sum[lc][i] * sum[rc][i] % mod * v[now][i] % mod * (cg0[now][i]<=0) *g[now][i] % mod;
		rs[now][i] = (rs[rc][i] + (cg0[now][i]<=0)*g[now][i]*(rs[lc][i]+1)%mod*v[now][i]%mod*sum[rc][i])%mod; 	
		ls[now][i] = (ls[lc][i] + (cg0[now][i]<=0)*g[now][i]*(ls[rc][i]+1)%mod*v[now][i]%mod*sum[lc][i])%mod;
		
		int tmp = (su[now][i]+mod)%mod;
		
		su[now][i] = (su[lc][i] + su[rc][i] + 
			(rs[lc][i]+1) * (ls[rc][i]+1)% mod
				* (cg0[now][i]<=0)*g[now][i] % mod * v[now][i] % mod
		+ gu[now][i]) % mod;
		
	}
}

void upd2(int now,int to,int tp){
	for(int i=0;i<m;i++){
		if((ls[now][i] + 1) % mod == 0)
			cg0[to][i] += tp;
		else 
			g[to][i] = g[to][i] * (tp == 1 ? ls[now][i] + 1 : inv[(ls[now][i]+1+mod)%mod]) % mod;
		gu[to][i] = (gu[to][i] + tp * su[now][i]) % mod;
	}
}

int Build(int l,int r,int pfa){
	if(l>r) return 0;
	int L = l , R = r , mid , haf = (siz[pos[l]] - (r+1<=pfa ? siz[pos[r+1]] : 0)) / 2;
	for(;L<R;){
		mid = (L+R) >> 1; 
		if(siz[pos[l]] - siz[pos[mid]] >= haf) R = mid;
		else L = mid + 1;
	}
	int now = pos[L];
	fa[ch[now][0] = Build(l,L-1,pfa)] = now;
	fa[ch[now][1] = Build(L+1,r,pfa)] = now;
	upd(now);
	
	//FWT(su[now],-1);
	//printf("%d %d %d\n",now,ch[now][0],ch[now][1]);
	//for(int i=0;i
	//FWT(su[now],1);
	
	
	return now;
}

int dfs2(int now,int ff){
	int be = tot + 1 , ed;
	for(int i=now;i!=-1;i=son[i])
		pos[id[i] = ++tot] = i;
	ed = tot;
	
	for(int p=now;p!=-1;p=son[p])
		for(int i=info[p];i;i=Prev[i])
			if(!id[to[i]]){
				int tmp = dfs2(to[i],p);
				fa[tmp] = p;
				upd2(tmp,p,1);
			}
	return Build(be,ed,ed);
}

int isr(int x){ return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x; }

int main(){
	scanf("%d%d",&n,&m);
	for(int i=2;i<mod;i++)
		inv[i] = (mod - mod / i) * inv[mod % i] % mod;
	for(int i=1;i<=n;i++){
		scanf("%d",&w[i]);
		v[i][w[i]] = 1;
		FWT(v[i],1);
	}
	for(int i=0;i<m;i++){
		val[i][i] = 1;
		FWT(val[i],1);
	}
	for(int i=0;i<=n;i++)
		for(int j=0;j<m;j++) 
			g[i][j] = sum[i][j] = 1;
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		Node(u,v),Node(v,u);
	}
	
	dfs1(1,0),rt=dfs2(1,0);
	int q;
	scanf("%d",&q);
	char S[10];
	for(int x,y;q--;){
		scanf("%s",S);
		if(S[0] == 'C'){
			scanf("%d%d",&x,&y);
			w[x] =y;
			memset(v[x],0,sizeof v[x]);
			v[x][y] = 1;
			FWT(v[x],1);
			if(isr(x) && fa[x]) upd2(x,fa[x],-1);
			upd(x);
			if(isr(x) && fa[x]) upd2(x,fa[x],1);
			for(x=fa[x];x;x=fa[x]){
				if(isr(x) && fa[x]) upd2(x,fa[x],-1);
				upd(x);
				if(isr(x) && fa[x]) upd2(x,fa[x],1);
			}
		}
		else{
			scanf("%d",&x);
			for(int i=0;i<m;i++) v[0][i] = su[rt][i];
			FWT(v[0],-1);
			printf("%d\n",(v[0][x]+mod)%mod);
		}
	}
}

你可能感兴趣的:(模板,数据结构,数论)