[Luogu3727]曼哈顿计划E

luogu

题意(简化版)

给你一棵树,每个点上有一个\(SG\)值,问你是否存在一条路径使得\(SG\)异或和为\(0\)

sol

可以当做每个点的稳定值就是这个点上的石子数量。
很显然我们只需要把每个点的\(SG\)值处理出来后面的就好做了。
分别考虑\(k\)的不同取值下的\(SG\)函数的计算方法。

\(k=1\)

每堆石子可以任意取,显然\(SG(x)=x\)

\(k=2\)

打表/手玩可以发现,若\(x\)恰好为\(S+1\)的倍数\(-1\)\(SG(x)=2\),否则\(SG(x)=x\%2\)

\(k=3\)

打表/手玩可以发现,\(SG(x)=\lfloor \frac{x}{S}\rfloor\)

\(k=4\)
打表可以发现,

\[SG(x)= \begin{cases} 0 & \text{ , } x= 0 \\ x & \text{ , } x\equiv 1,2 (mod\ 4) \\ x+1 & \text{ , } x\equiv 3 (mod\ 4) \\ x-1 & \text{ , } x\equiv 0 (mod\ 4) \end{cases} \]

剩下的就很简单了,点分治每次考虑所有过重心的路径。开\(set\)记录每个点到分治重心的异或和,注意对重心的处理。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<set>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 3e4+5;
int T,n,k,s,to[N<<1],nxt[N<<1],head[N],cnt,val[N];
int vis[N],sz[N],w[N],root,sum,val_top,fg;
set<int>S;
int SG(int x)
{
	if (k==1) return x;
	if (k==2) return (x+1)%(s+1)?x&1:2;
	if (k==3) return x/s;
	if (k==4){
		if (x==0) return 0;
		if (x%4==1||x%4==2) return x;
		if (x%4==3) return x+1;
		else return x-1;
	}
}
void link(int u,int v)
{
	to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void getroot(int u,int f)
{
	sz[u]=1;w[u]=0;
	for (int e=head[u];e;e=nxt[e])
		if (to[e]!=f&&!vis[to[e]])
		{
			getroot(to[e],u);
			sz[u]+=sz[to[e]];w[u]=max(w[u],sz[to[e]]);
		}
	w[u]=max(w[u],sum-sz[u]);
	if (w[u]<w[root]) root=u;
}
void dfs1(int u,int f,int sta)
{
	if (S.find(sta^val_top)!=S.end()) fg=1;
	for (int e=head[u];e;e=nxt[e])
		if (to[e]!=f&&!vis[to[e]])
			dfs1(to[e],u,sta^val[to[e]]);
}
void dfs2(int u,int f,int sta)
{
	S.insert(sta);
	for (int e=head[u];e;e=nxt[e])
		if (to[e]!=f&&!vis[to[e]])
			dfs2(to[e],u,sta^val[to[e]]);
}
void solve(int u)
{
	vis[u]=1;S.insert(0);val_top=val[u];
	for (int e=head[u];e;e=nxt[e])
		if (!vis[to[e]])
			dfs1(to[e],0,val[to[e]]),dfs2(to[e],0,val[to[e]]);
	S.clear();
	for (int e=head[u];e;e=nxt[e])
		if (!vis[to[e]])
		{
			sum=sz[to[e]];root=0;
			getroot(to[e],0);solve(root);
		}
}
int main()
{
	T=gi();
	while (T--)
	{
		n=gi();cnt=fg=0;
		memset(head,0,sizeof(head));
		memset(vis,0,sizeof(vis));
		for (int i=1;i<n;++i)
		{
			int u=gi(),v=gi();
			link(u,v);link(v,u);
		}
		for (int i=1;i<=n;++i) val[i]=gi();
		k=gi();if (k==2||k==3) s=gi();
		for (int i=1;i<=n;++i) val[i]=SG(val[i]);
		root=0;w[0]=sum=n;
		getroot(1,0);solve(root);
		if (fg) puts("Mutalisk ride face how to lose?");
		else puts("The commentary cannot go on!");
	}
	return 0;
}
posted @ 2018-04-12 16:17  租酥雨  阅读(312)  评论(0编辑  收藏  举报