传送门:loj2330
题解
先考虑根的情况(
Subtask 3
S
u
b
t
a
s
k
3
)。
根的每个儿子及其构成的子树之间可以互相抵消。
设
rem[i]
r
e
m
[
i
]
表示以
i
i
为根的子树最少的不能互相抵消的点数。
那么考虑根的最大儿子,
若
sz[1]−1−sz[mx[1]]≤rem[mx[1]]
s
z
[
1
]
−
1
−
s
z
[
m
x
[
1
]
]
≤
r
e
m
[
m
x
[
1
]
]
,大儿子可以被抵消掉,这时只需考虑
sz[1]−1
s
z
[
1
]
−
1
是否为偶数即可。
否则
rem[1]=rem[mx[1]]−sz[1]+sz[mx[1]]+2
r
e
m
[
1
]
=
r
e
m
[
m
x
[
1
]
]
−
s
z
[
1
]
+
s
z
[
m
x
[
1
]
]
+
2
其他
Subtask
S
u
b
t
a
s
k
,把当前节点到根节点的这条链看做根,顺便记一下每个点的第二大儿子
mxx[i],res[i]
m
x
x
[
i
]
,
r
e
s
[
i
]
存一下这条链为根的最大儿子。
dfs
d
f
s
一遍即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int W,T,n,d[N],sz[N],ans[N];
int rem[N],mx[N],mxx[N],f[N],res[N];
int head[N],to[N<<1],nxt[N<<1],tot;
inline int rd()
{
char ch=getchar();int x=0,f=1;
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
return x*f;
}
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
inline void dfs(int x)
{
int i,j;
d[x]=d[f[x]]+1;sz[x]=1;mx[x]=mxx[x]=0;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[x]) continue;
f[j]=x;dfs(j);sz[x]+=sz[j];
if(sz[mx[x]]<sz[j]){mxx[x]=mx[x];mx[x]=j;}
else if(sz[mxx[x]]<sz[j]) mxx[x]=j;
}
if(sz[x]-1-sz[mx[x]]>=rem[mx[x]]) rem[x]=((sz[x]-1)&1)+1;
else rem[x]=rem[mx[x]]-sz[x]+2+sz[mx[x]];
}
inline void df(int x)
{
int i,j;ans[x]=0;
if(!((sz[1]-d[x])&1)){
j=res[x];if(sz[mx[x]]>sz[res[x]]) j=mx[x];
if((sz[1]-d[x]-sz[j])>=rem[j]) ans[x]=1;
}
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==f[x]) continue;
res[j]=res[x];
if((j!=mx[x])&&(sz[mx[x]]>sz[res[j]])) res[j]=mx[x];
else if(sz[mxx[x]]>sz[res[j]]) res[j]=mxx[x];
df(j);
}
}
int main(){
int i,j,ix,iy;
W=rd(),T=rd();
while(T--){
n=rd();
for(tot=0,i=1;i<=n;++i) head[i]=0;
for(i=1;i<n;++i){ix=rd();iy=rd();lk(ix,iy);lk(iy,ix);}
dfs(1);
if(W==3){
if((!((sz[1]-1)&1)) && (sz[1]-1-sz[mx[1]])>=rem[mx[1]]) puts("1");
else puts("0");
}else{
res[1]=0;df(1);
for(i=1;i<=n;++i) printf("%c",'0'+ans[i]);
puts("");
}
}
}