BZOJ3218: A + B Problem

来源:互联网 发布:电脑程序员图片 编辑:程序博客网 时间:2024/06/05 02:22

BZOJ3218: A + B Problem

最小割·主席树

题解:

用主席树优化最小割orz

orz orz orz orz orz
orz orz orz orz orz
orz POPOQQQ orz
orz orz orz orz orz
orz orz orz orz orz

调试1.5h+

Code:

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <queue>#define D(x) cout<<#x<<" = "<<x<<"  "#define E cout<<endl using namespace std;typedef long long ll;const int N = 200005;const int INF = 0x3f3f3f3f;inline void read(int &num){    num=0; char c; int bo=1;    while(!isdigit(c=getchar()) && c!='-');    if(c=='-') bo=-1;    else num=c-'0';    while(isdigit(c=getchar())) num=num*10+c-'0';    num*=bo;}int S, T, n, tp[N], tpsz; ll ans;int a[5005],b[5005],w[5005],l[5005],r[5005],p[5005];int lch[N], rch[N], root[N], sz;struct Edge{    int to,next,cap,flow;} e[2000005];int head[N], ec=1;void add(int a,int b,int cap){    ec++; e[ec].cap=cap; e[ec].flow=0;    e[ec].to=b; e[ec].next=head[a]; head[a]=ec;}void add2(int a,int b,int cap){    add(a,b,cap); add(b,a,0);}int d[N]; bool vis[N];bool bfs(){    memset(vis,false,sizeof(vis));    memset(d,-1,sizeof(d));    queue<int> q; q.push(S); vis[S]=true; d[S]=0;    while(!q.empty()){        int u=q.front(); q.pop();        for(int i=head[u];i;i=e[i].next){            int v=e[i].to;            if(!vis[v] && e[i].cap>e[i].flow){                vis[v]=true; d[v]=d[u]+1; q.push(v);                if(v==T) return true;            }        }    }    return false;}int dfs(int u,int a){    if(u==T || a==0) return a;    int flow=0, f;    for(int i=head[u];i;i=e[i].next){        int v=e[i].to;        if(d[v]==d[u]+1 && (f=dfs(v,min(a,e[i].cap-e[i].flow)))){            e[i].flow+=f; e[i^1].flow-=f; flow+=f; a-=f;            if(a==0) break;        }    }    if(a) d[u]=-1;    return flow;}ll dinic(){    ll flow=0;    while(bfs()){ flow+=dfs(S,INF); }    return flow;}void insert(int &x,int t,int p,int id,int l=1,int r=tpsz){    x=++sz; lch[x]=lch[t]; rch[x]=rch[t];    add2(id,x+n*2,INF); if(t)add2(t+n*2,x+n*2,INF);         if(l!=r){        int mid=(l+r)>>1;        if(p<=mid){ insert(lch[x],lch[t],p,id,l,mid); }        else{ insert(rch[x],rch[t],p,id,mid+1,r); }    }}void find(int &x,int t,int ql,int qr,int id,int l=1,int r=tpsz){    if(!x) return;    if(ql<=l && r<=qr){ add2(x+n*2,id+n,INF); return; }    int mid=(l+r)>>1;    if(ql<=mid){ find(lch[x],lch[t],ql,qr,id,l,mid); }    if(qr>mid){ find(rch[x],rch[t],ql,qr,id,mid+1,r); }}void build(){    S=N-5; T=S+1;    for(int i=1;i<=n;i++){        add2(S,i,w[i]); add2(i,T,b[i]);        add2(i+n,i,p[i]);    }    for(int i=1;i<=n;i++){        if(i>1) find(root[i-1],root[i-2],l[i],r[i],i);        insert(root[i],root[i-1],a[i],i);    }}int main(){    freopen("3218.in","r",stdin);    read(n); tpsz=0;    for(int i=1;i<=n;i++){        read(a[i]); read(b[i]); read(w[i]);         read(l[i]); read(r[i]); read(p[i]);        ans+=w[i]; ans+=b[i];        tp[++tpsz]=a[i]; tp[++tpsz]=l[i]; tp[++tpsz]=r[i];    }    sort(tp,tp+tpsz); tpsz=unique(tp,tp+tpsz)-tp;//  D(tpsz); E;    for(int i=1;i<=n;i++){        a[i]=lower_bound(tp,tp+tpsz,a[i])-tp+1;        l[i]=lower_bound(tp,tp+tpsz,l[i])-tp+1;        r[i]=lower_bound(tp,tp+tpsz,r[i])-tp+1;//      D(a[i]); D(l[i]); D(r[i]); E;    }    build();    ans-=dinic();    printf("%lld\n",ans);}

最后来写一下我为啥一直WA。。。
出来手残少些了一些addedge外
罪魁祸首就是想着在一个root里面插入多条链,还想着这几条链公共部分共用点的zz主席树(你明白这是啥吧。。。不知道也没关系,可能只有我这种zz能想出这种zz写法。。。)
我一开始在查找区间的时候走到没有建立的点也新建点,其实根本就不用,直接返回就行了。因为下面没有点,反正也不会有流量。

总之不要像我这样zz!