图论题【1】

题意


input

5
1 2
2 3
3 4
4 5

output

1

限制与约定

\[3≤n≤200000\]

题解

如果只放一个点,很显然就是放在直径的中点上面,这样一定是最优的,
\[Ans=(len(直径)+1)/2\]而现在题目要求取两个点,
我们想象在两点路径的中点及其子树到两点的路径均相等,
而在中点右边(没有中点一样)到右边选的点的距离一定小于到左边选的点的距离。
当然,左边同理。
即现在题目要求断开一条边,然后使得两个部分的最长直径最短。
而断开这条边的位置,一定是在原来那棵树的直径上面。
于是呢,就把直径抽出来,把直径上每个点及其子树(子树不包括直径上其他点)
都记录一个最长直径,以及以这个点开始能走的最长距离与次长距离。
求出断开每一条边的左半部分的直径分别是多少,
在处理一遍右边的,组合一下就好了

code

#include <bits/stdc++.h>
#define re register int
#define inf 1e9
using namespace std;
inline void read(int &x){
    x=0;char ch=getchar();
    for(;!isdigit(ch);ch=getchar());
    for(; isdigit(ch);ch=getchar())
        x=(x<<1)+(x<<3)+(ch^48); 
}
inline void print(int x){if(x>9)print(x/10);putchar((x%10)+48);}
const int N=200010;
int n,q,f[N],to[N<<1],nx[N<<1],h[N],d[N],c,v[N],l[N][4],g[N],dis[N],ans=N;
inline void add(int u,int v){to[++c]=v,nx[c]=h[u],h[u]=c;}
inline void dfs(int x,int fa){
    f[x]=fa,d[x]=d[fa]+1;
    for(re i=h[x];i;i=nx[i])
        if(to[i]!=fa)dfs(to[i],x);
}
inline void get(int x,int fa){
    l[x][1]=l[x][2]=l[x][3]=0;
    for(re i=h[x];i;i=nx[i])
        if(to[i]!=fa&&!v[to[i]]){
            get(to[i],x);
            re tmp=l[to[i]][1]+1;
            if(tmp>=l[x][1])
                l[x][2]=l[x][1],l[x][1]=tmp;
            else if(tmp>l[x][2])l[x][2]=tmp;
            l[x][3]=max(l[to[i]][3],(l[x][1]+l[x][2]));
        }
}
signed main(){
    freopen("ob.in","r",stdin);
    freopen("ob.out","w",stdout); 
    read(n);int x,y,l1=0,l2=0;
    for(re i=1;i<n;++i) 
        read(x),read(y),add(x,y),add(y,x); 
    dfs(1,0);
    for(re i=1;i<=n;++i) if(d[i]>d[l1]) l1=i;
    dfs(l1,0);
    for(re i=1;i<=n;++i) if(d[i]>d[l2]) l2=i;
    for(re i=l2;i;i=f[i]) v[i]=1;
    for(re i=l2;i;i=f[i]) get(i,0);
    for(re i=l2;i;i=f[i]){
        g[f[i]]=i;
        re tmp=l[g[i]][1]+1;
        if(g[i]==0) tmp=0;
        if(tmp>=l[i][1])
            l[i][2]=l[i][1],l[i][1]=tmp;
        else if(tmp>l[i][2])l[i][2]=tmp;
        dis[i]=l[i][3]=max(l[g[i]][3],(l[i][1]+l[i][2]));
    }
    for(re i=l2;i;i=f[i]) get(i,0);
    for(re i=l1;i;i=g[i]){
        re tmp=l[f[i]][1]+1;
        if(f[i]==0) tmp=0;
        if(tmp>=l[i][1])
            l[i][2]=l[i][1],l[i][1]=tmp;
        else if(tmp>l[i][2])l[i][2]=tmp;
        l[i][3]=max(l[f[i]][3],(l[i][1]+l[i][2]));
        ans=min(ans,max(l[i][3],dis[g[i]]));
    }
    print((ans+1)>>1);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Sparks-Pion/p/9691346.html