zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    第十五节课:习题讲解
    第十四节课:字典
    Python第十三节课-文件的读取和写入
    Python第十二节课--循环语句与注释
    Python第十一节课--字符串的格式化
    Python第十节课==对象的方法
    Python第九节课--初识函数
    初识函数--文件的读取和打开,已一节课一节课分开,可不看
    刷题647. Palindromic Substrings
    刷题617. Merge Two Binary Trees
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8521860.html
Copyright © 2011-2022 走看看