【CF1632E2】Distance Tree
作者:互联网
还是不错的树论题,但是不太明白E1的意义。
分析:
容易发现直接连 \((1,u)\) 这样的边是最优秀的。
我们考虑一个判定性问题:对于某个确定的 \(x\) 和 \(ans\),怎么判断答案是否 \(<=ans\)。
定义点 \(u\) 深度 \(d(u)\) 为 \(1\) 到 \(u\) 经过的边数,显然 \(d(u)\le ans\) 的点可以忽略,剩下的点仅靠树上的边不足以满足要求,所以它们必须经过新加的边。
如果新加的边为 \((1,u)\),那么要找的是 \(d(u)>ans\) 的点里离点 \(u\) 最远的点的距离。
这个问题很有意思,如果给你一颗完整的,边权全为 \(1\) 的树,那我们都会做这个问题,答案是树的直径 \(v\) 的 \(\left\lfloor \frac{v}{2} \right\rfloor\),取的点是直径上中点。
想想这个是咋证明的,是不是分两部分:1. 如果取的不是中点是其它点,答案的下界肯定比 \(\left\lfloor \frac{v}{2} \right\rfloor\) 大。2. 取这个点的时候,不可能有其它的点到它的距离还要大了,否则与树的直径的定义矛盾。
回到本题,你发现我们可以套用上面的方法来证明一个自然的想法:设 \(S(u)\) 是所有深度大于 \(u\) 的点的集合,定义 \(dp(u)=\max\{dis(x,y)\mid x,y\in S(u)\}\),那么当且仅当 \(\left\lfloor \frac{dp(ans)}{2} \right\rfloor+x \le ans\) 的时候才可行。
这里还有一个细节:当集合 \(|S|=1\) 的时候,是要保证 \(x\le ans\) 的,但如果 \(|S|=0\) 即 \(ans>maxdepth\) 那 \(x\) 的取值不重要了,一定可行。
然后考虑 \(dp(u)\) 的计算,直接 \(n^2\) 枚举点对不可行。还是套用树的直径里的内容:类似求树直径的 dp 方法一样,我们枚举 lca。假设当前枚举到了点 \(u\) 为 lca,我们选出的两点一定是最深的子树和次深的子树,记深度为 \(x\) 和 \(x'\),那么实质上会更新到 \(dp(x'-1)\sim dp(0)\) 上,但是这样又变成 \(n^2\) 修改了。发现每次修改都是一个前缀的形式,所以可以作类似差分的事情:打标记。就是如果我们对 \([1,i]\) 这个前缀有一次和 \(val\) 取 \(\min\) 的运算,那么先给 \(tag_i:=\max\{tag_i,val\}\),最后 \(i\) 降序枚举,执行 \(dp_i=\max\{dp_{i+1},tag_i\}\) 就好了。
然后有个事情,就是 \(ans\) 随着 \(x\) 递增而递增(不下降),这个很显然。所以最后双指针一下就好了,判断已经说过了。时间复杂度 \(O(n)\),非常牛逼。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define op(x) ((x&1)?x+1:x-1)
#define odd(x) (x&1)
#define even(x) (!odd(x))
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define lowbit(x) (x&-x)
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define next Cry_For_theMoon
#define il inline
#define pb(x) push_back(x)
#define is(x) insert(x)
#define sit set<int>::iterator
#define mapit map<int,int>::iterator
#define pi pair<int,int>
#define ppi pair<int,pi>
#define pp pair<pi,pi>
#define fr first
#define se second
#define vit vector<int>::iterator
#define mp(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
using namespace std;
const int MAXN=3e5+10;
int n,t;
int depth[MAXN],f[MAXN],dp[MAXN];
vector<int>e[MAXN];
void dfs1(int u,int fa){
depth[u]=f[u]=depth[fa]+1;
for(auto v:e[u]){
if(v==fa)continue;
dfs1(v,u);
f[u]=max(f[u],f[v]);
}
}
void dfs2(int u,int fa){
int max1=depth[u],max2=depth[u];
for(auto v:e[u]){
if(v==fa)continue;
dfs2(v,u);
if(f[v]>max1)max2=max1,max1=f[v];
else if(f[v]>max2)max2=f[v];
}
if(max2==0)return;
dp[max2-1]=max(dp[max2-1],max1+max2-2*depth[u]);
}
void solve(){
scanf("%d",&n);rep(i,1,n)e[i].clear(),dp[i]=0;
rep(i,1,n-1){
int u,v;scanf("%d%d",&u,&v);e[u].pb(v);e[v].pb(u);
}
depth[0]=-1;
dfs1(1,0);
dfs2(1,0);
per(i,n-1,0)dp[i]=max(dp[i],dp[i+1]);
for(int l=1,r=0;l<=n;l++){
while(r<f[1] && (dp[r]+1)/2+l>r)r++;
printf("%d ",r);
}
printf("\n");
}
int main(){
scanf("%d",&t);
while(t--)solve();
return 0;
}
标签:Distance,int,Tree,max2,depth,ans,CF1632E2,dp,define 来源: https://www.cnblogs.com/Cry-For-theMoon/p/15861965.html