zoukankan      html  css  js  c++  java
  • bzoj4919: 大根堆

    Description

    给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。
    你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j。
    请计算可选的最多的点数,注意这些点不必形成这棵树的一个连通子树。

    Input

    第一行包含一个正整数n(1<=n<=200000),表示节点的个数。
    接下来n行,每行两个整数v_i,p_i(0<=v_i<=10^9,1<=p_i<i,p_1=0),表示每个节点的权值与父亲。

    Output

    输出一行一个正整数,即最多的点数。
    平衡树启发式合并,维护当前子树内选k个点,选出的点权最大值的最小值
    #include<bits/stdc++.h>
    const int N=200007;
    char buf[70007],*ptr=buf+70000;
    int G(){
        if(ptr-buf==70000)fread(ptr=buf,1,70000,stdin);
        return *ptr++;
    }
    int _(){
        int x=0;
        if(ptr-buf<69900){
            while(*ptr<48)++ptr;
            while(*ptr>47)x=x*10+*ptr++-48;
        }else{
            int c=G();
            while(c<48)c=G();
            while(c>47)x=x*10+c-48,c=G();
        }
        return x;
    }
    int n;
    int v[N],fa[N],q[N],ql=0,qr=0,deg[N];
    std::multiset<int>vs[N];
    typedef std::multiset<int>::iterator mit;
    int main(){
        n=_();
        for(int i=1;i<=n;++i){
            v[i]=_();
            ++deg[fa[i]=_()];
        }
        for(int i=1;i<=n;++i)if(!deg[i])q[++qr]=i;
        while(ql!=qr){
            int w=q[++ql],f=fa[w];
            mit u=vs[w].lower_bound(v[w]);
            if(u==vs[w].end())vs[w].insert(v[w]);
            else *const_cast<int*>(&*u)=v[w];
            if(f){
                if(vs[f].size()<vs[w].size())std::swap(vs[f],vs[w]);
                for(mit it=vs[w].begin(),e=vs[w].end();it!=e;++it)vs[f].insert(*it);
                vs[w].clear();
                if(!--deg[f])q[++qr]=f;
            }
        }
        printf("%d
    ",vs[1].size());
        return 0;
    }
  • 相关阅读:
    ORA12560: TNS: 协议适配器错误的问题
    ibatis代码生成工具abator使用全过程
    DbHelper数据操作类
    眼睛有干涩、血丝、怕光,流泪,甚至红肿的现象吗
    Dot.Net代码生成器
    两分钟让你明白什么是ERP
    spring的b/s项目中配置log4j
    十面埋妇
    程序员发展的目标
    标准体重计算查询
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7122930.html
Copyright © 2011-2022 走看看