题目
题意:
给出一棵树(n<=4e5),可以有一次机会:删除一条边,然后添加一条边,使之仍然是树。
现在对于每个点,最多有一次机会,是否可以保证与它相连的子树大小不超过n/2。(删掉这个点后,所有连通分量的结点数<=n/2)
解法:
1.删去任一结点x,最多只会有一棵树的size>=n/2
2.对于这棵树的补救措施就是将其中一部分移到别处。
3.只能是一部分,因为全部移到别处更加不能满足要求。
4.删去的一部分也是一棵树。
5.需要将这棵树的根结点作为x的子结点,这样才是最优的。
两次dfs,依次处理出dp[x](子树x的size),up[x] (=n-dp[x])
cutd[x] (对于子树x,能移除的树的最大size,注意x不能移除,否则不满足还是不满足),注意这个大小要控制在[0,n/2]内,否则移动到哪都不行。这棵树必须是x的后代结点)
cutu[x] (x的祖辈中,就是x往上走,能移除的树最大size,注意不包括x本身)
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define mes(a,x,s) memset(a,x,(s)*sizeof a[0])
#define mem(a,x) memset(a,x,sizeof a)
#define ysk(x) (1<<(x))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn=400000 ;
int n;
vector<int >G[maxn+5];
int dp[maxn+5],up[maxn+5];
int ok[maxn+5],cutd[maxn+5],cutu[maxn+5];
void dfs(int x,int fa)
{
int siz=G[x].size(),ret=0;
dp[x]=1;cutd[x]=0;
ok[x]=1;
for0(i,siz)
{
int y=G[x][i];if(y==fa) continue;
dfs(y,x);
dp[x]+=dp[y];
if(dp[y]>n/2)
{
if( dp[y]-cutd[y]>n/2 ) ok[x]=-1;
}
cutd[x]=max(cutd[x],cutd[y]);
if(dp[y]<=n/2) cutd[x]=max(cutd[x],dp[y]);
}
up[x]=n-dp[x];
if(up[x]>n/2) ok[x]=0;
}
int pre[maxn+5],suf[maxn+5],pos[maxn+5],np;
void dfs2(int x,int fa)
{
int siz=G[x].size(),np=0;
for0(i,siz)
{
int y=G[x][i];if(y==fa) continue;
pos[++np]=y;
}
pre[x]=0;
for1(i,np)
{
int y=pos[i];
int ret=cutd[y ];
if(dp[y]<=n/2) ret=max(ret,dp[y]);
pre[i]=max(pre[i-1],ret);
}
suf[np+1]=0;
for(int i=np;i>=1;i--)
{
int y=pos[i];
int ret=cutd[y ];
if(dp[y]<=n/2) ret=max(ret,dp[y]);
suf[i]=max(suf[i+1],ret);
}
for1(i,np)
{
int y=pos[i];
int tmp=max(pre[i-1],suf[i+1]);
tmp=max(tmp,cutu[x]);
if(up[y]<=n/2) tmp=max(tmp,up[y]);
cutu[y]=tmp;
if(!ok[y] &&up[y]-cutu[y] <=n/2) ok[y]=1;
}
for0(i,siz)
{
int y=G[x][i];if(y==fa) continue;
dfs2(y,x);
}
}
int main()
{
std::ios::sync_with_stdio(false);
int x,y;
while(cin>>n)
{
for1(i,n) G[i].clear();
for0(i,n-1)
{
cin>>x>>y;
G[x].push_back(y);G[y].push_back(x);
}
dfs(1,-1);
cutu[1]=0;dfs2(1,-1);
for1(i,n)
{
putchar( ok[i]==1?'1':'0');
putchar( i==n?'\n':' ');
}
}
return 0;
}