• 51nod1803 森林直径



    题目看这里
    (为什么xhEditor不能支持字体了,不管了,那就用markdown吧)

    一个非常有意思的题目,首先考虑离线做法,把所有的询问按照l排序,所有的边倒序插入整个树中
    我们需要维护两个东西:
    1.f[x][i]表示当整颗树有[x,f[x][i]]这一个区间内的所有边时,以x为根的子树存在一个深度为i的儿子,满足条件最小的f[x][i]
    2.g[k]表示最小的r,使得[l,r]组成的森林拥有长度为k的直径
    那么每次加入一条边(x,y) (x为y的祖先) 我们就需要更新这两个东西:
    g[i+j+1]=min(g[i+j+1],max(f[x][i],f[y][j],y-1)) (注意y-1就是这条边的编号)
    f[x][i]=min(f[x][i],max(y-1,f[y][j-1])
    注意到题目的性质,树高是log n级别的
    所以一次操作是O(log n) 的,一共n次加边,总复杂度O(n lg n)

    (再也弄不回原来的code风格了,否则就是没有高亮的了)

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define M 35
    #define N 500010
    using namespace std;
    struct Q{ int l,r; } s[N];
    int n,m,f[N][M],g[M<<2],p[N],A;
    inline bool cmp(Q a,Q b){ return a.l==b.l?a.r>b.r:a.l>b.l; }
    inline void adj(int x,int y){
        for(int i=0;i<M;++i) if(f[x][i]<n)
            for(int j=0;j<M;++j) g[i+j+1]=min(g[i+j+1],max(max(f[x][i],f[y][j]),y-1));
        for(int i=0;i<M;++i) f[x][i]=min(f[x][i],max(f[y][i-1],y-1));
    }
    int main(){
        scanf("%d",&n); memset(f,0x3f,sizeof f);
        for(int i=1;i<n;++i) scanf("%d%*d",p+i),f[i][0]=0;
        scanf("%d",&m); f[n][0]=0;
        for(int i=1;i<=m;++i) scanf("%d%d",&s[i].l,&s[i].r);
        sort(s+1,s+1+m,cmp); memset(g,0x3f,sizeof g);
        for(int i=n-1,j=1;i&&j<=m;--i){
            adj(p[i],i+1);
            for(int k=M*2;j<=m&&s[j].l==i;++j)
                for(++k;;--k) if(g[k]<=s[j].r) { A+=k; break; }
        }
        printf("%d
    ",A);
    }

  • 相关阅读:
    HTTP解析
    Linux(CentOS)常用命令
    Windows下虚拟Linux
    国内静态文件CDN服务介绍 国内js公共库
    吐槽一下csdn和博客园
    项目托管 网站 小记
    微软2013年校园实习生招聘笔试题及答案
    最近在折腾VPS(持续完善)
    spring MVC +freemarker + easyui 实现sql查询和执行小工具总结
    Hessian 接口使用示例总结
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477080.html
Copyright © 2020-2023  润新知