1 条题解
-
0
设 为 子树 的结点与 的结点数量差。
显然在染色方案确定时需要 ,此时答案为 。(考虑子树内贪心配对,剩下 个结点配对时需要走 这条边,这条边的边权为 ,这里 为 的父亲)。
最大值最小,考虑二分一个 ,要求所有 ,且 。
设 为 子树内是否可以使得 。
强制所有 的 ,直接做树上背包即可做到 。
注意到对于一个 , 的结点 恰好是一个区间 内的所有奇数(子树大小是奇数时)或所有偶数(子树大小为偶数时)。
所以树形背包时只需要对于每个结点计算 的区间 即可。
时间复杂度被优化到了 。可以通过。
#include<bits/stdc++.h> using namespace std; const int N=400100; vector<int> T[N]; int n,l[N],r[N],c[N]; bool dfs(int u,int f,int k){ l[u]=(c[u]==1?1:-1),r[u]=(c[u]==2?-1:1); for(int v:T[u]) if(v!=f){ if(!dfs(v,u,k)) return 0; l[u]+=l[v],r[u]+=r[v]; } int nl=max(l[u],-k),nr=min(r[u],k); if((nl-l[u])%2!=0) ++nl; if((nr-r[u])%2!=0) --nr; l[u]=nl,r[u]=nr; return l[u]>r[u]?0:1; } bool check(int mid){ if(!dfs(1,0,mid)) return 0; return l[1]<=0&&r[1]>=0; } int main(){ ios::sync_with_stdio(0),cin.tie(0); cin>>n; for(int i=1;i<=2*n;i++) cin>>c[i]; for(int i=1,u,v;i<2*n;i++) cin>>u>>v,T[u].push_back(v),T[v].push_back(u); int L=1,R=n,mid,ans; while(L<=R){ mid=(L+R)>>1; if(check(mid)) ans=mid,R=mid-1; else L=mid+1; } return cout<<ans<<'\n',0; }
信息
- ID
- 307
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 3
- 已通过
- 2
- 上传者