题解:CF2035F Tree Operations
Statement
给定一棵以
若第
求出
数据范围:数据组数
Solution
首先,如果存在
问题变为如何判定一个操作次数
这样我们可以在
给出结论:一定存在一种有限次操作方案完成题目的要求。注意可以使用
- 首先可以进行若干次操作,将所有位置都变为
0 或1 。 - 取一个非根结点的结点
y ,考虑让除了根结点x 之外所有结点的值都变得与y 相同。每次取一个与y 不同的结点z ,可以使用n 次操作:操作目标为x, z 时令结点z 取反,操作其余结点时令其自身取反。这样可以在O(n^2) 次操作内让除了根结点之外的所有结点的值全变为0 或全变为1 。 - 若
x 的值与其余结点不同并且x \neq 1 ,那么再使用上面的n 次操作让结点1 和x 之外的所有结点取反,此时只有结点1 与其他结点不同。 - 如果结点
1 之外的点的值为1 ,那么用n 次操作全局取反。 - 最后若结点
1 的值为1 ,用一次操作将1 变为0 。
故不存在无解的情况。
Solution (English)
First, if there exists a plan with
The problem then becomes how to determine if a number of operations
This allows us to determine feasibility in
In conclusion, there definitely exists a finite sequence of operations to meet the problem's requirements. Note that we can use
- First, we can perform several operations to make all positions either
0 or1 . - Choose a non-root node
y and consider making all nodes except for the root nodex have the same value asy . Each time, take a nodez that has a different value thany ; we can usen operations: when the targets arex andz , flip nodez , and for the remaining nodes, flip themselves. This way, withinO(n^2) operations, all nodes except for the root can be made either0 or1 . - If the value of
x is different from the other nodes andx \neq 1 , then use the previousn operations to flip all nodes except for node1 andx ; at this point, only node1 will differ from the others. - If the values of the nodes except for node
1 are all1 , then perform a global flip usingn operations. - Finally, if the value of node
1 is1 , perform one operation to change it to0 .
Thus, there are no cases with no solution.
Code
#include<bits/stdc++.h>
using namespace std;
int n,root,a[2001];
vector<int> E[2001];
long long f[2001],g[2001];
int dfn[2001],rnk[2001],fa[2001],cntdfn;
void init(int u,int father){
fa[u]=father,dfn[u]=++cntdfn,rnk[cntdfn]=u;
for(int v :E[u])if(v!=father)init(v,u);
}
inline bool check(long long val){
for(int i=1;i<=n;i++)f[i]=val/n+(i<=val%n),g[i]=a[i];
f[0]=g[0]=0;
for(int i=n;i>=1;i--){
int u=rnk[i];
g[fa[u]]+=f[u]<g[u]?g[u]-f[u]:((f[u]-g[u])&1);
}
return g[0]==0;
}
int main(){
int T; scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&root);
for(int i=1;i<=n;i++)E[i].clear();
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
E[u].push_back(v);
E[v].push_back(u);
}
cntdfn=0;
init(root,0);
long long answer=1e18;
for(int i=0;i<n*2;i++){
int l=0,r=1e9;
while(l<r){
int mid=(l+r)>>1;
if(check(1ll*mid*n*2+i))r=mid;
else l=mid+1;
}
answer=min(answer,1ll*l*n*2+i);
}
printf("%lld\n",answer);
}
return 0;
}