• Codeforces#514E(贪心,并查集)


    #include<bits/stdc++.h>
    using namespace std;
    long long w[100007],sum[100007];
    int fa[100007],degree[100007],dp[100007],depth[100007];
    int flag[100007];
    int vis[100007];
    int find_x(int x)//非递归并查集
    {
        int k, j, r;
        r = x;
        while(r != dp[r])     //查找根节点
            r = dp[r];      //找到根节点,用r记录下
        k = x;
        while(k != r)             //非递归路径压缩操作
        {
            j = dp[k];         //用j暂存parent[k]的父节点
            dp[k] = r;        //fa[x]指向根节点
            k = j;                    //k移到父节点
        }
        return r;         //返回根节点的值
    }
    int main(){
        int n,l;
        long long s;
        scanf("%d%d%lld",&n,&l,&s);
        for(int i=1;i<=n;i++){
            scanf("%lld",&w[i]);
            if(w[i]>s)//这个权重超重
                return puts("-1"),0;
        }
        for(int i=2;i<=n;i++){
            scanf("%d",&fa[i]);
            degree[fa[i]]++;//双亲结点度数+1
        }
        for(int i=1;i<=n;i++){
            dp[i]=i;
            depth[i]=depth[fa[i]]+1;//深度为双亲结点深度+1
            sum[i]=sum[fa[i]]+w[i];//这一点的总权重为双亲结点总权重+自己权重
        }
        int h=0,cnt=0,ans=0;
        for(int i=1;i<=n;i++){
            if(!degree[i])//i为叶子节点
                flag[cnt++]=i;//记录叶子节点位置
        }
        while(h<cnt){
            int x=flag[h++];
            if(vis[x])
                continue;
            ans++;
            int num=0;
            long long val=0;
            while(x){
                int next=find_x(x);//第一次是自己,之后是祖先(它被合并入它的双亲)
                if(vis[next]==1)//当它变成祖先时,这个向上贪心的点已经被选中
                    break;//这句去掉一样能过,多跑15ms,感觉加上比较好
                num+=depth[x]-depth[next]+1;//这一条路的节点数
                val+=sum[x]-sum[next]+w[next];////这一条路的总权重
                if(num>l||val>s)//超长或者超重就停止,无法继续贪心
                    break;
                vis[next]=1;//这个节点已经被选中,所有的点都只能被选中一次
                degree[fa[next]]--;//next的双亲结点度数减一
                if(!degree[fa[next]])//如果nect的双亲结点成为叶子节点
                    flag[cnt++]=fa[next];//记录它的位置
                dp[next]=find_x(fa[dp[next]]);//把这个点并到它父亲里
                x=fa[next];//贪心它的父亲
            }
        }
        printf("%d ",ans);
        return 0;
    }
    /*while(h<t)
        {
            int x=q[h++];
            if(vis[x]) continue;
            ++Ans;
            int num=0; LL s=0;
            while(x)
            {
                int nxt=Find(x);
                num+=depth[x]-depth[nxt]+1, s+=sum[x]-sum[nxt]+w[nxt];
                if(num>L||s>S) break;
                vis[nxt]=1;
                if(!--dgr[fa[nxt]]) q[t++]=fa[nxt];
                F[nxt]=Find(fa[F[nxt]]), x=fa[nxt];
            }
        }
        printf("%d ",Ans);*/
    保持热爱 不懈努力 不试试看怎么知道会失败呢(划掉) 世上无难事 只要肯放弃(划掉)
  • 相关阅读:
    eclipse快捷键
    ideaIU-2017.3.2版本的免费安装以及2020版本破解
    并发相关问题以及java基础知识
    飞秋软件-局域网内互传
    视频解析网站
    bzoj2458: [BeiJing2011]最小三角形
    bzoj3170: [Tjoi2013]松鼠聚会
    bzoj5056:OI游戏
    dtoj#4224. 小L的占卜
    dtoj#4222. 小b爱旅行(travel)
  • 原文地址:https://www.cnblogs.com/ldudxy/p/9769105.html
Copyright © 2020-2023  润新知