zoukankan      html  css  js  c++  java
  • bzoj4068: [Ctsc2015]app

    Description

    幽香是幻想乡中一个非常有地位的人。她日理万机,事务繁多,反倒自己已经快管理不过来了。于是他决定开发一个日程管理软件来帮助自己管理任务。 

    对于每个任务i有一个对应的截止日期ti以及收益pi,表示若幽香能在不晚于第ti天完成这个任务,便可以得到pi的收益。幽香办事的能力非常强,任何任务都可以用恰好一天的时间做完。但由于任务实在太多了,有时候并不能完成所有任务,于是幽香会想知道这个情况下,完成任务可以给她带来的最大的累积收益是多少。 
    由于幻想乡的人们十分善变,任务总是不断发生着变化。幽香希望这个管理软件还能够支持插入一个任务,和删除一个任务的操作。 
    具体的说,幽香希望支持以下2个操作: 
    1.ADD t p:表示新添一个截止日期为t,收益为p的任务。 
    2.DEL t p:表示删除一个截止日期为t,收益为p的任务。如果有多个这样的任务,只删除一个。数据保证这样的任务一定存在。 
    在每次操作执行完毕后,你都需要输出能够完成的任务的最大收益和。 
    幽香一共有T天需要安排,从第1天到第T天。你能帮助他写出这个高效率的软件吗? 

    Input

    第一行有两个证书T和Q,表示天数和操作的个数。 

    接下来Q行,其中第i行表示第i个操作,形式为ADD t p或DEL t p,其具体意义如题面所述。 

    Output

    对每一次操作,输出一个整数在执行完该操作后幽香能够获得的最大收益和。 

    考虑用最大费用流表示这个贪心(每一天拆一个点x,x到x-1连费用0流量无限的边,x到T连费用0流量1的边,任务表示为S到x的流量1费用为收益的边),对于每次ADD,相当于加入一条边,这时如果有到T的增广路就直接增广(可以做这个任务而不影响其余任务),否则若可以找到正费用的增广环(用这个任务换掉一个收益更小的任务)也可以增广,否则不操作;

    对于每次DEL,如果这条边没增广,就直接删边,否则需要退掉经过这条边的流量,优先考虑找一个增广环(相当于用另一个任务换掉当前任务),找不到再考虑增广路(直接删去当前任务)。

    由于图的特殊性,可以用线段树和平衡树等维护增广过程。

    #include<bits/stdc++.h>
    const int M=1e5,N=300007,inf=INT_MAX;
    char ib[M+7],*ip=ib+M;
    int G(){
        if(ip==ib+M)fread(ip=ib,1,M,stdin)[ib]=0;
        return *ip++;
    }
    int _(){
        int x=0,f=1;
        if(ip<ib+M-100){
            while(*ip<48)*ip++=='-'?f=-1:0;
            while(*ip>47)x=x*10+*ip++-48;
        }else{
            int c=G();
            while(c<48)c=G();
            while(c>47)x=x*10+c-48,c=G();
        }
        return x*f;
    }
    int min(int a,int b){return a<b?a:b;}
    int max(int a,int b){return a>b?a:b;}
    int _l,_r,_a;
    struct node{
        node*lc,*rc;
        int L,R,M;
        int mn,a;
        void add(int x){mn+=x,a+=x;}
        void dn(){if(a)lc->add(a),rc->add(a),a=0;}
        void up(){mn=min(lc->mn,rc->mn);}
        void add(){
            if(_l<=L&&R<=_r)return add(_a);
            dn();
            if(_l<=M)lc->add();
            if(_r>M)rc->add();
            up();
        }
        bool ql(){
            if(mn)return 0;
            if(L==R)return _l=L,1;
            return dn(),_r>M&&rc->ql()||lc->ql();
        }
        bool qr(){
            if(mn)return 0;
            if(L==R)return _r=R,1;
            return dn(),_l<=M&&lc->qr()||rc->qr();
        }
    }ns[N*2],*np=ns,*rt;
    node*build(int L,int R){
        node*w=np++;
        w->L=L,w->R=R;
        if(L<R){
            int M=w->M=L+R>>1;
            w->lc=build(L,M);
            w->rc=build(M+1,R);
        }
        return w;
    }
    int gr(int x){return _l=x,rt->qr(),_r;}
    int gl(int x){return _r=x-1,rt->ql(),_l+1;}
    void flow(int x,int y){
        if(x<y)_l=x,_r=y-1,_a=-1,rt->add();
        if(x>y)_l=y,_r=x-1,_a=1,rt->add();
    }
    std::multiset<int>e0[N],e1[N];
    std::multiset<int>::iterator it;
    long long ans=0;
    int n,qp,t1[1055555],t0[1055555],mx;
    int em[1055555];
    int pv_empty(int w){
        for(w+=mx+1;;w>>=1)if(w&1&&em[w-1]&1){
            for(--w;w<mx;w<<=1,w+=em[w+1]&1);
            return w-mx;
        }
    }
    int nx_full(int w){
        for(w+=mx-1;w;w>>=1)if(~w&1&&em[w+1]&2){
            for(++w;w<mx;w=w<<1^1,w-=em[w-1]>>1&1);
            return w-mx;
        }
        return 0;
    }
    void set_(int w,int v){
        for(w+=mx,em[w]=v,w>>=1;w;w>>=1)em[w]=em[w<<1]|em[w<<1^1];
    }
    void upd1(int w){
        t1[w+mx]=e1[w].size()?*e1[w].begin():inf;
        for(w=w+mx>>1;w;w>>=1)t1[w]=min(t1[w<<1],t1[w<<1^1]);
    }
    void upd0(int w){
        t0[w+mx]=e0[w].size()?*--e0[w].end():-inf;
        for(w=w+mx>>1;w;w>>=1)t0[w]=max(t0[w<<1],t0[w<<1^1]);
    }
    int gmn(int l,int r){
        int w=mx+l;
        for(l+=mx-1,r+=mx+1;r-l!=1;l>>=1,r>>=1){
            if(~l&1&&t1[l+1]<t1[w])w=l+1;
            if(r&1&&t1[r-1]<t1[w])w=r-1;
        }
        for(;w<mx;w=w<<1^(t1[w<<1^1]==t1[w]));
        return w-mx;
    }
    int gmx(int l,int r){
        int w=mx+l;
        for(l+=mx-1,r+=mx+1;r-l!=1;l>>=1,r>>=1){
            if(~l&1&&t0[l+1]>t0[w])w=l+1;
            if(r&1&&t0[r-1]>t0[w])w=r-1;
        }
        for(;w<mx;w=w<<1^(t0[w<<1^1]==t0[w]));
        return w-mx;
    }
    int ins(int x,int y){
        int p=gr(x),pe=pv_empty(p);
        if(pe){
            flow(x,pe);
            set_(pe,2);
            e1[x].insert(y);
            upd1(x);
            return y;
        }else{
            int z=gmn(1,p),zv=t1[mx+z];
            if(zv<y){
                flow(x,z);
                e1[x].insert(y);
                e1[z].erase(e1[z].find(zv));
                e0[z].insert(zv);
                upd1(x),upd1(z),upd0(z);
                return y-zv;
            }else{
                e0[x].insert(y);
                upd0(x);
                return 0;
            }
        }
    }
    int del(int x,int y){
        if((it=e0[x].find(y))!=e0[x].end()){
            e0[x].erase(it);
            upd0(x);
            return 0;
        }else{
            e1[x].erase(e1[x].find(y));
            upd1(x);
            int p=gl(x),z=gmx(p,n),zv=t0[mx+z];
            if(zv>=0){
                flow(z,x);
                e1[z].insert(zv);
                e0[z].erase(e0[z].find(zv));
                upd1(z),upd0(z);
                return zv-y;
            }
            int pf=nx_full(p);
            flow(pf,x);
            set_(pf,1);
            return -y;
        }
    }
    int main(){
        n=_();
        rt=build(0,n);
        for(mx=1;mx<n+5;mx<<=1);
        for(int i=0;i<mx*2;++i)t1[i]=inf,t0[i]=-inf,em[i]=1;
        for(qp=_();qp;--qp){
            int o=_(),a=_(),b=_();
            printf("%lld
    ",ans+=o==1920?ins(a,b):del(a,b));
        }
        return 0;
    }
  • 相关阅读:
    C语言 exit 函数 C语言零基础入门教程
    C/C++ getchar函数 C语言零基础入门教程
    自己动手重新实现LINQ to Objects: 7 Count和LongCount
    自己动手重新实现LINQ to Objects: 5 Empty
    自己动手重新实现LINQ to Objects: 8 Concat
    自己动手重新实现LINQ to Objects: 11 First,Last,Single以及它们带有OrDefault的重载
    自己动手重新实现LINQ to Objects: 3 Select
    自己动手重新实现LINQ to Objects: 2 Where
    自己动手重新实现LINQ to Objects: 10 Any和All
    用豆瓣读书Chrome插件,简单购买电子书
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7567975.html
Copyright © 2011-2022 走看看