ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CF1632E2】Distance Tree

2022-02-03 21:06:39  阅读:183  来源: 互联网

标签:Distance int Tree max2 depth ans CF1632E2 dp define


传送门

还是不错的树论题,但是不太明白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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有