zoukankan      html  css  js  c++  java
  • 图论题【1】

    题意


    input

    5
    1 2
    2 3
    3 4
    4 5
    

    output

    1
    

    限制与约定

    (3≤n≤200000)

    题解

    如果只放一个点,很显然就是放在直径的中点上面,这样一定是最优的,

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

  • 相关阅读:
    [翻译]跟我一起边译边学之Linux:目录
    [翻译]跟我一起边译边学之Linux:致谢 Acknowledgments
    计算机图形学资源收集01
    计算机图形学资源收集02
    计算机图形学资源收集04
    计算机图形学资源收集03
    C#二十几种设计模式事例下载(源码)
    在WinForm应用程序中嵌入WPF控件
    .net网站与Winform窗体的数据交互(JS调用Winform后台方法实现)
    C#调用rar.exe解压一个rar文件
  • 原文地址:https://www.cnblogs.com/Sparks-Pion/p/9691346.html
Copyright © 2011-2022 走看看