• BZOJ4890 Tjoi2017城市


      显然删掉的边肯定是直径上的边。考虑枚举删哪一条。然后考虑怎么连。显然新边应该满足其两端点在各自树中作为根能使树深度最小。只要线性求出这个东西就可以了,这与求树的重心的过程类似。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 5010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,p[N],deep[N],fa[N],f[N],len[N],t,root,ans=N*N;
    bool flag[N];
    struct data{int to,nxt,len;
    }edge[N<<1];
    void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;}
    void dfs(int k) 
    {
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=fa[k])
        {
            deep[edge[i].to]=deep[k]+edge[i].len;
            fa[edge[i].to]=k;
            len[edge[i].to]=edge[i].len;
            dfs(edge[i].to);
        }
    }
    int dp(int k,int ban)
    {
        flag[k]=1;
        int mx=0,mx2=0,ans=0;
        for (int i=p[k];i;i=edge[i].nxt)
        if (!flag[edge[i].to]&&edge[i].to!=ban)
        {
            ans=max(ans,dp(edge[i].to,ban));
            int x=f[edge[i].to]+edge[i].len;
            if (x>mx) mx2=mx,mx=x;
            else if (x>mx2) mx2=x;
        }
        f[k]=mx;
        return max(ans,mx+mx2);
    }
    int findroot(int k,int ban,int last)
    {
        int mx=0,mx2=0,l=0,len=0;
        for (int i=p[k];i;i=edge[i].nxt)
        if (edge[i].to!=fa[k]&&edge[i].to!=ban)
        {
            int x=f[edge[i].to]+edge[i].len;
            if (x>mx) mx2=mx,mx=x,l=edge[i].to,len=edge[i].len;
            else if (x>mx2) mx2=x;
        }
        if (max(last,mx2)+len<mx) return findroot(l,ban,max(last,mx2)+len);
        else return k;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4890.in","r",stdin);
        freopen("bzoj4890.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read(),z=read();
            addedge(x,y,z),addedge(y,x,z);
        }
        dfs(1);
        int root=1;for (int i=2;i<=n;i++) if (deep[i]>deep[root]) root=i;
        fa[root]=deep[root]=0;dfs(root);
        int x=1;for (int i=2;i<=n;i++) if (deep[i]>deep[x]) x=i;
        while (x!=root)
        {
            memset(f,0,sizeof(f));
            memset(flag,0,sizeof(flag));
            int t=max(dp(root,x),dp(x,fa[x]));
            int u=findroot(root,x,0),v=findroot(x,fa[x],0);
            memset(f,0,sizeof(f));
            memset(flag,0,sizeof(flag));
            dp(u,x),dp(v,fa[x]);
            ans=min(ans,max(f[u]+f[v]+len[x],t));
            x=fa[x];
        }
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    拼接数组的几种方法
    小议GetHashCode()方法
    如何在窗体间传递数据!
    设置TextBox控件的滚动条位置
    关于Console.Read()方法的一些误解!
    从内存布局角度谈谈值类型和引用类型!
    在Windows线程中模拟其他用户上下文!
    将文本插入TextBox控件的光标位置!
    用C#实现屏幕键盘!
    CLR的程序集定位算法
  • 原文地址:https://www.cnblogs.com/Gloid/p/10031368.html
Copyright © 2020-2023  润新知