• [USACO10HOL]牛的*Cow Politics


    农夫约翰的奶牛住在N (2 <= N <= 200,000)片不同的草地上,标号为1到N。恰好有N-1条单位长度的双向道路,用各种各样的方法连接这些草地。而且从每片草地出发都可以抵达其他所有草地。也就是说,这些草地和道路构成了一种叫做树的图。输入包含一个详细的草地的集合,详细说明了每个草地的父节点P_i (0 <= P_i <= N)。根节点的P_i == 0, 表示它没有父节点。因为奶牛建立了1到K一共K (1 <= K <= N/2)个政党。每只奶牛都要加入某一个政党,其中, 第i只奶牛属于第A_i (1 <= A_i <= K)个政党。而且每个政党至少有两只奶牛。 这些政党互相吵闹争。每个政党都想知道自己的“范围”有多大。其中,定义一个政党的范围是这个政党离得最远的两只奶牛(沿着双向道路行走)的距离。
    输入输出格式
    输入格式:
    * Line 1: Two space-separated integers: N and K
    * Lines 2..N+1: Line i+1 contains two space-separated integers: A_i and P_i
    输出格式:
    * Lines 1..K: Line i contains a single integer that is the range of party i.
    输入输出样例
    输入样例#16 2 
    1 3 
    2 1 
    1 0 
    2 1 
    2 1 
    1 5 
    输出样例#13 
    2 
    题面

    首先需要知道在只有一个政党的情况下,

    题目弱化为求一个树中最远的两个点的距离,这个是可以用两遍BFS的方法求出,

    具体步骤为:
    随便选择一个节点x,BFS求出距离x最远的节点y(有相同的随便选)。
    以节点y为起点,BFS求出距离y最远的节点z(有相同的随便选)。
    节点y和节点z之间的距离,就是这棵树中最远距离。
    有了上面这个之后,在本题中,我们对每个政党都做一遍这个方法即可,

    但是我们不能进行BFS了。注意到BFS只是为了求距离最远的点,

    那么如果我们可以通过其他方法来求得任意两点间距离的话,步骤就可以转变为:
    随便选择该政党的一个节点x,枚举该政党的其他节点,求出距离x最远的节点y。
    以节点y为起点,枚举该政党的其他节点,求出距离y最远的节点z。
    节点y和节点z的距离,就是该政党的最远距离。
    对于求树上任意两点间的距离,一般转化为求LCA的,即
    Dist(x, y) = Depth(x) + Depth(y) - 2 * Depth(LCA(x, y))
    求LCA的方法有很多,这里就不再描述了。

    #include<bits/stdc++.h> 
    using namespace std;
    const int N=2e5+20;
    int h[N],n,tot,k;
    struct node{
        int v,ne;
    }e[N];
    void add(int u,int v)
    {
        tot++;e[tot]=(node){v,h[u]};h[u]=tot;
    }
    int rt,f[N][30],d[N];
    vector<int>bg[N/2];
    void dfs(int x)
    {
        for(int i=h[x];i;i=e[i].ne)
        {
            int rr=e[i].v;
            d[rr]=d[x]+1;
            dfs(rr);
        }
    }
    int lca(int x,int y)
    {
        if(d[x]<d[y]) swap(x,y);
        int h=d[x]-d[y];
        for(int j=27;j>=0;--j)
         if((1<<j)&h) x=f[x][j];
        for(int j=27;j>=0;--j)
         if(f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
        if(x==y) return x;
        else return f[x][0];
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1,x,y;i<=n;++i)
        {
            scanf("%d%d",&x,&y);
            bg[x].push_back(i);
            if(y) add(y,i),f[i][0]=y;
            else rt=i;
        }
        d[rt]=1;dfs(rt);
        for(int j=1;j<=27;++j)
         for(int i=1;i<=n;++i)
          f[i][j]=f[f[i][j-1]][j-1];
        for(int i=1,x,y,z,dis;i<=k;++i)
        {
            x=bg[i][0];y=0;
            for(int j=1;j<bg[i].size();++j)
            {
                dis=d[bg[i][j]]+d[x]-2*d[lca(bg[i][j],x)];
                if(dis>y) y=dis,z=bg[i][j];
            }
            y=0;
            for(int j=0;j<bg[i].size();++j)
            {
                dis=d[bg[i][j]]+d[z]-2*d[lca(bg[i][j],z)];
                if(dis>y) y=dis,x=bg[i][j];
            }
            printf("%d
    ",y);
        }
        return 0;
    }
    代码
  • 相关阅读:
    BFPRT算法O(n)解决第k小的数
    Manacher练习
    KMP全家桶练习
    Codeforces Round #552 (Div. 3)
    Manacher's Algorithm
    poj 2559 (单调栈)
    单调队列
    单调栈
    multiset用法
    poj3660 Cow Contest(Floyd-Warshall方法求有向图的传递闭包)
  • 原文地址:https://www.cnblogs.com/adelalove/p/9135521.html
Copyright © 2020-2023  润新知