题目
https://codeforces.com/contest/1110/problem/G
题目大意
给你一棵树,树上的节点有的是白色,有的是无色。接着有两个操控白色和黑色的人进行游戏,按白、黑、白、黑的顺序依次操作,每次操作可以将一个无色的节点染成自己的颜色。如果出现了一条含3个节点的同色路径,那么操控那种颜色的人胜利。若到无法操作时仍未决出胜负,则是平局。
有T组询问 ( 1 ≤ T ≤ 50000 ) (1≤T≤50000) (1≤T≤50000),树的节点个数为n ( 1 ≤ n ≤ 5 ⋅ 1 0 5 ) (1≤n≤5⋅10^5) (1≤n≤5⋅105)。
题解
一开始我发现了几个结论:
- 黑色不可能赢。因为一开始白色方是有优势的,如果黑色能赢,那么白色按照它的下法来操作必定能赢;
- 只用考虑初始图中是否含有白色必胜的子图即可。
然后我就开始分类讨论,结果发现既要考虑白色点,又要考虑无色点,提交之后发现漏考虑的情况一个接一个。于是索性放弃,手动模拟了好多个数据后,发现一个白色点等价于一个连接一个 有2个无色点儿子的无色点儿子 的无色点(懒得画图)。
接着白色必胜的情况就只有3种了:
- 存在度数大于等于4的节点;
- 存在连接至少2个度数大于等于2的点和额外的1个点的点;
- 不符合以上两种情况,且拥有两个度数大于等于3的点的连通图,要求这两个点之间的最短路径的边数为偶数。
于是就AC了。
CODE
#include<cstdio>
using namespace std;
#define win {white=1;goto print;}
#define M 2000005
int deg1[M],deg2[M],x[M],y[M],fir[M],to[4000005],nex[4000005],data[M],cnt,s;
char c[500005];bool dis[M],vis[M];
inline void bfs(int k)
{
for(int i=1;i<=cnt;++i) dis[i]=vis[i]=0;
int head=0,tail=1,u,v;
data[1]=k,vis[k]=1;
while(head<tail)
{
u=data[++head];
for(int i=fir[u];i;i=nex[i]) if(!vis[to[i]])
{
v=to[i];
dis[v]=dis[u]^1;
data[++tail]=v;
vis[v]=1;
}
}
}
inline void inc(int x,int y)
{
to[++s]=y,nex[s]=fir[x],fir[x]=s;
to[++s]=x,nex[s]=fir[y],fir[y]=s;
}
int main()
{
int t,n,m,i,j,u,v;bool white,flag;
scanf("%d",&t);
for(j=1;j<=t;++j)
{
scanf("%d",&n),m=n-1,cnt=n;
u=v=0,white=0,flag=1;
for(i=1;i<=n;++i) deg1[i]=deg2[i]=fir[i]=0;
for(i=1;i<n;++i) scanf("%d%d",x+i,y+i),inc(x[i],y[i]);
scanf("%s",c+1);
for(i=1;i<=n;++i) if(c[i]=='W')
{
fir[cnt+1]=fir[cnt+2]=fir[cnt+3]=0;
deg1[cnt+1]=deg1[cnt+2]=deg1[cnt+3]=0;
deg2[cnt+1]=deg2[cnt+2]=deg2[cnt+3]=0;
x[++m]=i,y[m]=cnt+1,inc(i,cnt+1);
x[++m]=cnt+1,y[m]=cnt+2,inc(cnt+1,cnt+2);
x[++m]=cnt+1,y[m]=cnt+3,inc(cnt+1,cnt+3);
cnt+=3;
}
for(i=1;i<=m;++i) ++deg1[x[i]],++deg1[y[i]];
for(i=1;i<=m;++i)
{
if(deg1[x[i]]>1) ++deg2[y[i]];
if(deg1[y[i]]>1) ++deg2[x[i]];
}
for(i=1;i<=cnt;++i)
{
if(deg1[i]==3)
{
if(!u) u=i;
else if(!v) v=i;
else flag=0;
}
if(deg1[i]>3) win
if(deg1[i]>2&°2[i]>1) win
}
if(flag&&u&&v) bfs(u),white=!dis[v];
print:puts(white?"White":"Draw");
}
return 0;
}