1 条题解

  • 0
    @ 2025-10-8 17:07:04

    C17 左偏树 P1552 [APIO2012] 派遣

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=100005;
    int n,m;
    int fa[N],pay[N],lead[N]; //原树节点信息
    int ls[N],rs[N],dis[N],siz[N],root[N]; //左偏树
    long long sum[N],ans;
    
    int merge(int x,int y){
      if(!x||!y) return x+y;
      if(pay[x]<pay[y]) swap(x,y); //大根堆
      rs[x]=merge(rs[x],y);
      
      if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
      dis[x]=dis[rs[x]]+1;
      return x;
    }
    int main(){
      scanf("%d%d",&n,&m); dis[0]=-1;
      for(int i=1; i<=n; i++){
        scanf("%d%d%d",&fa[i],&pay[i],&lead[i]);
        root[i]=i; //每个节点看成一个单独的堆
        siz[i]=1;
        sum[i]=pay[i];
        ans=max(ans,1ll*lead[i]);//选一个节点的贡献
      }
      for(int i=n; i>1; i--){ //从叶子节点向上枚举
        int f=fa[i];
        root[f]=merge(root[i],root[f]);
        siz[f]+=siz[i]; sum[f]+=sum[i];
        while(sum[f]>m){ //循环删除堆中点权大的节点
          siz[f]--; sum[f]-=pay[root[f]];
          root[f]=merge(ls[root[f]],rs[root[f]]);
        }
        ans=max(ans, 1ll*lead[f]*siz[f]);
      }
      cout<<ans;
    }
    
    // 左偏树+树形DP
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=100005;
    int n,m;
    int pay[N],lead[N]; //原树节点信息
    int ls[N],rs[N],dis[N],siz[N],root[N]; //左偏树
    long long sum[N],ans;
    
    int h[N],to[N],ne[N],tot;
    void add(int a, int b){
      to[++tot]=b;ne[tot]=h[a];h[a]=tot;
    }
    int merge(int x,int y){
      if(!x||!y) return x+y;
      if(pay[x]<pay[y]) swap(x,y); //大根堆
      rs[x]=merge(rs[x],y);
      
      if(dis[ls[x]]<dis[rs[x]]) swap(ls[x],rs[x]);
      dis[x]=dis[rs[x]]+1;
      return x;
    }
    void dfs(int x){
      siz[x]=1,sum[x]=pay[x];
      for(int i=h[x]; i; i=ne[i]){
        int y=to[i]; dfs(y);
        root[x]=merge(root[x],root[y]);
        siz[x]+=siz[y]; sum[x]+=sum[y];
      }
      while(sum[x]>m){
        siz[x]--; sum[x]-=pay[root[x]];
        root[x]=merge(ls[root[x]],rs[root[x]]);
      }
      ans=max(ans,1ll*lead[x]*siz[x]);
    }
    int main(){
      scanf("%d%d",&n,&m);
      dis[0]=-1; int rt;
      for(int i=1,f; i<=n; ++i){
        scanf("%d%d%d",&f,&pay[i],&lead[i]);
        if(f) add(f,i);
        else rt=i;
        root[i]=i; //每个节点看成一个单独的堆
      }
      dfs(rt);
      cout<<ans;
    }
    
    • 1

    信息

    ID
    4474
    时间
    500ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    3
    已通过
    2
    上传者