• bzoj2809: [Apio2012]dispatching


    这题老号用左偏树写过。

    然后现在用了主席树,感觉理解加深了很多。

    首先就是dfs序搞出每个节点管理的区间,然后暴力枚举每一个管理者,然后在区间里找最多能够支付多少人。

    值得注意的是当前位置的值应该是排序后的数组的值而非原来当前位置的值,调了一中午。。

    主席树:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    
    int n;LL m;
    LL c[210000],ld[210000];
    
    struct node
    {
        int x,y,next;
    }a[210000];int len,last[210000];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    
    
    struct chairtree
    {
        int lc,rc;
        LL c,sum;
    }tr[4100000];int trlen,rt[210000];
    int maketree(int now,int l,int r,LL k,LL s)
    {
        if(now==0)now=++trlen;
        tr[now].c++, tr[now].sum+=s;
        if(l<r)
        {
            int mid=(l+r)/2;
            if(k<=mid)tr[now].lc=maketree(tr[now].lc,l,mid,k,s);
            else       tr[now].rc=maketree(tr[now].rc,mid+1,r,k,s);
        }
        return now;
    }
    int merge(int x,int y)
    {
        if(x==0||y==0)return x+y;
        tr[x].c+=tr[y].c;
        tr[x].sum+=tr[y].sum;
        tr[x].lc=merge(tr[x].lc,tr[y].lc);
        tr[x].rc=merge(tr[x].rc,tr[y].rc);
        return x;
    }
    LL tt[210000];
    LL C,P;bool bk;
    void getpeople(int x,int y,int l,int r)
    {
        if(bk==false)return ;
        LL cc=tr[x].c-tr[y].c,sum=tr[x].sum-tr[y].sum;
        if(C+sum<=m)
        {
            C+=sum, P+=cc;
            if(C+tt[l]>m)bk=false;
        }
        else if(l==r)
        {
            LL bi=min((m-C)/tt[l],cc);
            C+=bi*tt[l], P+=bi;
            if(bi==0)bk=false;
        }
        else 
        {
            int mid=(l+r)/2;
            getpeople(tr[x].lc,tr[y].lc,l,mid);
            getpeople(tr[x].rc,tr[y].rc,mid+1,r);
        }
    }
    
    LL erfen(LL k)
    {
        int l=1,r=n,ret;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(tt[mid]<=k)
            {
                ret=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        return ret;
    }
    int root,z,l[210000],r[210000];
    void dfs(int x)
    {
        l[x]=++z;
        rt[z]=maketree(rt[z],1,n,erfen(c[x]),c[x]);
        rt[z]=merge(rt[z],rt[z-1]);
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            dfs(y);
        }
        r[x]=z;
    }
    
    int main()
    {
        int fa;
        scanf("%d%lld",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%lld%lld",&fa,&c[i],&ld[i]);tt[i]=c[i];
            if(fa==0)root=i;
            else ins(fa,i);
        }
        sort(tt+1,tt+n+1);
        z=0;trlen=0;dfs(root);
        
        LL mmax=0;
        for(int i=1;i<=n;i++)
        {
            C=0;P=0;bk=true;
            getpeople(rt[r[i]],rt[l[i]-1],1,n);
            mmax=max(mmax,ld[i]*P);
        }
        printf("%lld
    ",mmax);
        return 0;
    }

    左偏树:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    int n,m;
    struct node
    {
        int x,y,next;
    }a[1100000];int len,last[1100000];
    struct heap
    {
        int    l,r;
        LL c,d;
        heap()
        {
            l=r=d=0;
        }
    }h[1100000];
    int root[1100000];
    void ins(int x,int y)
    {
        len++;
        a[len].x=x;a[len].y=y;
        a[len].next=last[x];last[x]=len;
    }
    int Marge(int x,int y)
    {
        if(x==0||y==0)return x+y;
        if(h[x].c<h[y].c)swap(x,y);//按工资维护大根堆,踢堆首维护花费小于m方便 
        h[x].r=Marge(h[x].r,y);
        if(h[h[x].l].d<h[h[x].r].d)swap(h[x].l,h[x].r);
        h[x].d=h[h[x].r].d+1;
        return x;
    }
    LL p[1100000],s[1100000];//人数,花费钱数 
    LL ans,ld[1100000];
    void dfs(int x)//通过dfs序,使得每个点都成为一个大根堆,涵盖所有情况 
    {
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            dfs(y);
            p[x]+=p[y];s[x]+=s[y];
            root[x]=Marge(root[x],root[y]);
        }
        while(s[x]>m)
        {
            s[x]-=h[root[x]].c;p[x]--;
            root[x]=Marge(h[root[x]].l,h[root[x]].r);
        }
        if(ld[x]*p[x]>ans)ans=ld[x]*p[x];
    }
     
    int main()
    {
        int B;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%lld%lld",&B,&h[i].c,&ld[i]);
            ins(B,i);p[i]=1;s[i]=h[i].c;root[i]=i;
        }
        ans=0;dfs(1);
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    hdu 5734 Acperience
    报错解决
    测试代码出错
    fast rcnn训练自己数据小结
    top命令
    读csv文件
    计算机的屏幕坐标
    用virtualenv构建一个新的python环境,这个新的环境在这个创建的文件夹下
    python tips
    将目录下所有文件名修改为统一格式
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8521860.html
Copyright © 2020-2023  润新知