【bzoj3218】a + b Problem 【网络流】【最小割】【主席树】

题目传送门
题解:
考虑一种朴素的连边:
S>iw[i]
i>Tb[i]
i>ip[i]
j>i(1j<i,l[i]a[j]r[i])inf
然后用i=1nb[i]+w[i]减去最小割就是答案。
但是这样连边有n2级别的边数,n5000,显然不行。
于是我们就有了一些神奇的操作:主席树优化连边!
先把a,l,r进行一波离散化。
连边方法:
S>iw[i]
i>Tb[i]
i>ip[i]
主席树上,儿子向父亲连边,容量inf。
当要创建一个新版本时,上一个版本原来位置的节点向新增的log n个相同位置的节点连边,容量inf。新增的节点向其父亲连边,容量infia[i]在线段树上对应的叶子节点连边。
然后第i1个版本中[l[i],r[i]]在树上对应的一堆区间节点向i连边,容量inf
详细解释可以去看PoPoQQQ神犇的博客
吐槽:为什么我的常数那么大!为什么我的代码那么矬!
UPD:网络流模板有问题,work数组简直就是害人的!增加运行时间的利器!
代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5005,M=1200005,inf=0x7fffffff;
int n,tot=1,a[N],b[N],w[N],l[N],r[N],p[N],Hash[N];
int cnt=1,s=0,t=1,root[N],head[M],work[M],to[M],nxt[M],dd[M],dep[M],ch[M][2];
ll ans;
queue<int> q;
void adde(int u,int v,int d){
    to[++cnt]=v;
    nxt[cnt]=head[u];
    dd[cnt]=d;
    head[u]=cnt;
    to[++cnt]=u;
    nxt[cnt]=head[v];
    dd[cnt]=0;
    head[v]=cnt;
}
void build(int &x,int l,int r){
    x=++tot;
    if(l==r){
        return;
    }
    int mid=(l+r)/2;
    adde(tot+1,x,inf);
    build(ch[x][0],l,mid);
    adde(tot+1,x,inf);
    build(ch[x][1],mid+1,r);
}
void update(int y,int &x,int l,int r,int k,int node){
    x=++tot;
    ch[x][0]=ch[y][0];
    ch[x][1]=ch[y][1];
    adde(y,x,inf);
    if(l==r){
        adde(node,x,inf);
        return;
    }
    int mid=(l+r)/2;
    adde(tot+1,x,inf);
    if(k<=mid){
        update(ch[y][0],ch[x][0],l,mid,k,node);
    }else{
        update(ch[y][1],ch[x][1],mid+1,r,k,node);
    }
}
void get(int x,int l,int r,int L,int R,int nnode){
    if(L<=l&&R>=r){
        adde(x,nnode,inf);
        return;
    }
    int mid=(l+r)/2;
    if(L<=mid){
        get(ch[x][0],l,mid,L,R,nnode);
    }
    if(R>mid){
        get(ch[x][1],mid+1,r,L,R,nnode);
    }
}
bool bfs(){
    memset(dep,0,sizeof(int)*(tot+1));
    while(!q.empty()){
        q.pop();
    }
    dep[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front(),v;
        q.pop();
        for(int i=head[u];i;i=nxt[i]){
            v=to[i];
            if(dd[i]&&!dep[v]){
                dep[v]=dep[u]+1;
                if(v==t){
                    return true;
                }
                q.push(v);
            }
        }
    }
    return false;
}
ll dfs(int u,int f){
    if(u==t){
        return f;
    }
    int v;
    ll res=0,tmp;
    for(int &i=work[u];i&&f;i=nxt[i]){
        v=to[i];
        if(dd[i]&&dep[v]==dep[u]+1&&(tmp=dfs(v,min(f,dd[i])))){
            dd[i]-=tmp;
            dd[i^1]+=tmp;
            f-=tmp;
            res+=tmp;
        }
    }
    if(!res){
        dep[u]=0;
    }
    return res;
}
ll maxflow(){
    ll res=0;
    while(bfs()){
        memcpy(work,head,sizeof(int)*(tot+1));
        res+=dfs(s,0x7fffffff);
    }
    return res;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d%d%d%d%d",&a[i],&b[i],&w[i],&l[i],&r[i],&p[i]);
        Hash[++Hash[0]]=a[i];
        ans+=b[i]+w[i];
    }
    Hash[++Hash[0]]=inf;
    sort(Hash+1,Hash+Hash[0]+1);
    Hash[0]=unique(Hash+1,Hash+Hash[0]+1)-Hash-1;
    for(int i=1;i<=n;i++){
        a[i]=lower_bound(Hash+1,Hash+Hash[0]+1,a[i])-Hash;
        l[i]=lower_bound(Hash+1,Hash+Hash[0]+1,l[i])-Hash;
        r[i]=upper_bound(Hash+1,Hash+Hash[0]+1,r[i])-Hash-1;
    }
    build(root[0],1,Hash[0]);
    for(int i=1;i<=n;i++){
        int node=++tot,nnode=++tot;
        adde(s,node,w[i]);
        adde(node,t,b[i]);
        adde(nnode,node,p[i]);
        update(root[i-1],root[i],1,Hash[0],a[i],node);
        if(l[i]<=r[i]){
            get(root[i-1],1,Hash[0],l[i],r[i],nnode);
        }
    }
    printf("%lld\n",ans-maxflow());
    return 0;
}
posted @ 2018-06-08 21:02  一剑霜寒十四洲  阅读(139)  评论(0编辑  收藏  举报