其他分享
首页 > 其他分享> > P1552 [APIO2012]派遣

P1552 [APIO2012]派遣

作者:互联网

思路

复习下左偏树
左偏树首先满足堆性质,其次定义了一个dis,使得每个点的dis都是右子树dis+1,且左子树的dis>=右子树的dis
合并过程可以参考FHQ treap的merge进行修改
一开始看错题了,是选择的人要能跟所有派遣者通信(等价于是选择子树中的点),不是选中一个人使他变得可以与所有人通信
观察到代价之和领导力和选择的人的数量最多,所以派出人应当数量最多,用大根堆维护这个性质,然后在枚举每个人当作首领的情况,把其他子树合并过来之后继续维护选出数量最多且总和小于m的性质,然后更新ans即可
记得开longlong

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
struct Node{
    int num,lson,rson,dis,sum,sz,fa;
}LT[100100];
int fa[100100],c[100100],L[100100],n,m,ans,root;
int u[100100<<1],v[100100<<1],fir[100100],nxt[100100<<1],cnt;
void addedge(int ui,int vi){
    ++cnt;
    u[cnt]=ui;
    v[cnt]=vi;
    nxt[cnt]=fir[ui];
    fir[ui]=cnt;
}
void init(void){
    for(int i=1;i<=n;i++){
        LT[i].num=LT[i].sum=c[i];
        LT[i].sz=1;
        LT[i].fa=i;
        LT[i].lson=LT[i].rson=0;
        LT[i].dis=1;
    }
}
void pushup(int o){
    LT[o].sum=LT[LT[o].lson].sum+LT[LT[o].rson].sum+LT[o].num;
    LT[o].sz=LT[LT[o].lson].sz+LT[LT[o].rson].sz+1;
}
int findroot(int o){
    if(LT[o].fa==o)
        return o;
    return LT[o].fa=findroot(LT[o].fa);
}
int merge(int x,int y){
    if((!x)||(!y))
        return x+y;
    if(LT[x].num<LT[y].num)
        swap(x,y);
    LT[x].rson=merge(LT[x].rson,y);
    if(LT[LT[x].lson].dis<LT[LT[x].rson].dis)
        swap(LT[x].lson,LT[x].rson);
    LT[x].dis=LT[LT[x].rson].dis+1;
    LT[LT[x].lson].fa=LT[LT[x].rson].fa=LT[x].fa=x;
    pushup(x);
    return x;
}
int top(int x){
    return LT[findroot(x)].num;
}
void pop(int x){
    LT[LT[x].lson].fa=LT[x].lson;
    LT[LT[x].rson].fa=LT[x].rson;
    LT[x].fa=merge(LT[x].lson,LT[x].rson);
}
void dfs(int x){
    for(int i=fir[x];i;i=nxt[i]){
        if(v[i]==fa[x])
            continue;
        dfs(v[i]);
        merge(findroot(x),findroot(v[i]));
    }
    while(LT[findroot(x)].sum>m)
        pop(findroot(x));
    ans=max(ans,LT[findroot(x)].sz*L[x]);
}
signed main(){
    scanf("%lld %lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld %lld %lld",&fa[i],&c[i],&L[i]);
        if(fa[i]==0)
            root=i;
        else{
            addedge(fa[i],i);
            addedge(i,fa[i]);
        }
    }
    init();
    dfs(root);
    printf("%lld\n",ans);
    return 0;
}

标签:include,APIO2012,左偏,100100,int,P1552,ans,派遣,dis
来源: https://www.cnblogs.com/dreagonm/p/10514657.html