天天看點

BZOJ3218: A + B ProblemBZOJ3218: A + B Problem

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 = ;
const int INF = ;

inline void read(int &num){
    num=; char c; int bo=;
    while(!isdigit(c=getchar()) && c!='-');
    if(c=='-') bo=-;
    else num=c-'0';
    while(isdigit(c=getchar())) num=num*+c-'0';
    num*=bo;
}

int S, T, n, tp[N], tpsz; ll ans;
int a[],b[],w[],l[],r[],p[];
int lch[N], rch[N], root[N], sz;

struct Edge{
    int to,next,cap,flow;
} e[];
int head[N], ec=;
void add(int a,int b,int cap){
    ec++; e[ec].cap=cap; e[ec].flow=;
    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,);
}

int d[N]; bool vis[N];
bool bfs(){
    memset(vis,false,sizeof(vis));
    memset(d,-,sizeof(d));
    queue<int> q; q.push(S); vis[S]=true; d[S]=;
    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]+; q.push(v);
                if(v==T) return true;
            }
        }
    }
    return false;
}

int dfs(int u,int a){
    if(u==T || a==) return a;
    int flow=, f;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(d[v]==d[u]+ && (f=dfs(v,min(a,e[i].cap-e[i].flow)))){
            e[i].flow+=f; e[i^].flow-=f; flow+=f; a-=f;
            if(a==) break;
        }
    }
    if(a) d[u]=-;
    return flow;
}

ll dinic(){
    ll flow=;
    while(bfs()){ flow+=dfs(S,INF); }
    return flow;
}

void insert(int &x,int t,int p,int id,int l=,int r=tpsz){
    x=++sz; lch[x]=lch[t]; rch[x]=rch[t];
    add2(id,x+n*,INF); if(t)add2(t+n*,x+n*,INF);     
    if(l!=r){
        int mid=(l+r)>>;
        if(p<=mid){ insert(lch[x],lch[t],p,id,l,mid); }
        else{ insert(rch[x],rch[t],p,id,mid+,r); }
    }
}

void find(int &x,int t,int ql,int qr,int id,int l=,int r=tpsz){
    if(!x) return;
    if(ql<=l && r<=qr){ add2(x+n*,id+n,INF); return; }
    int mid=(l+r)>>;
    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+,r); }
}

void build(){
    S=N-; T=S+;
    for(int i=;i<=n;i++){
        add2(S,i,w[i]); add2(i,T,b[i]);
        add2(i+n,i,p[i]);
    }

    for(int i=;i<=n;i++){
        if(i>) find(root[i-],root[i-],l[i],r[i],i);
        insert(root[i],root[i-],a[i],i);
    }
}

int main(){
    freopen("3218.in","r",stdin);
    read(n); tpsz=;
    for(int i=;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=;i<=n;i++){
        a[i]=lower_bound(tp,tp+tpsz,a[i])-tp+;
        l[i]=lower_bound(tp,tp+tpsz,l[i])-tp+;
        r[i]=lower_bound(tp,tp+tpsz,r[i])-tp+;
//      D(a[i]); D(l[i]); D(r[i]); E;
    }
    build();
    ans-=dinic();
    printf("%lld\n",ans);
}
           

最後來寫一下我為啥一直WA。。。

出來手殘少些了一些addedge外

罪魁禍首就是想着在一個root裡面插入多條鍊,還想着這幾條鍊公共部分共用點的zz主席樹(你明白這是啥吧。。。不知道也沒關系,可能隻有我這種zz能想出這種zz寫法。。。)

我一開始在查找區間的時候走到沒有建立的點也建立點,其實根本就不用,直接傳回就行了。因為下面沒有點,反正也不會有流量。

總之不要像我這樣zz!

繼續閱讀