bzoj3218 a + b Problem(网络流+主席树)


$ans=\sum_{color_i=black}\ b_i+\sum_{color_i=white}\ w_i-\sum_{i=abnormal}\ p_i$

把它转化一下

$ans=\sum_{i=1}^{n}(b_i+w_i)-\sum_{color_i=black}\ w_i-\sum_{color_i=white}\ b_i-\sum_{i=abnormal}\ p_i$

这不是最小割--最大权闭合子图的套路吗!

设$S$割为黑点集合,$T$割为白点集合

怎么处理奇怪的方格?套路地把$i$拆成$i_1,i_2$

对于每个点$i$:

$links(S,i_1,b_i),link(i_1,T,w_i),link(i_1,i_2,p_i)$

对于每个$j<i,l_i<a_j<r_i$,$link(i_2,j_1,inf)$

于是你就可以AC拿到部分分辣!

但是由于出题人毒瘤的搞大数据,还需要优化

注意到每次连边时$j$都需要枚举,复杂度$O(n^2)$

考虑用主席树把复杂度降到$(nlogn)$

先把所有$a_i,l_i,r_i$拿来搞一遍离散化做主席树的下标

处理到点$i$时,先在主席树上查询$[l_i,r_i]$包含的区间,直接把$i_2$连到那个区间上去,$link(i_2,o,inf)$

蓝后再把点$i$按$a_i$加入到主席树上包含$a_i$的区间内,$link(o,i_1,inf)$

别忘了和上个版本连起来$link(o,p,inf)$

最终:$ans=\sum_{i=1}^{n}(b_i+w_i)-dinic()$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
#define N 100005
#define M 2000005
const int inf=2e9;
int n,S,T,cur[N],d[N]; ll ans;
int m,b[N],L[N],R[N],A[N];
int u,rt[N],lc[N],rc[N];
queue <int> h; bool vis[N];
int cnt=1,hd[N],nxt[M],ed[N],poi[M];ll val[M];
inline void adde(int x,int y,int v){
    nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt,
    ed[x]=cnt, poi[cnt]=y, val[cnt]=v;
}
inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);}
bool bfs(){
    for(int i=1;i<=u;++i) vis[i]=0,cur[i]=hd[i];
    h.push(S); vis[S]=1;
    while(!h.empty()){
        int x=h.front(); h.pop();
        for(int i=hd[x];i;i=nxt[i]){
            int to=poi[i];
            if(!vis[to]&&val[i]>0)
                vis[to]=1,d[to]=d[x]+1,h.push(to);
        }
    }return vis[T];
}
ll dfs(int x,ll a){
    if(x==T||a==0) return a;
    ll F=0,f;
    for(int &i=cur[x];i;i=nxt[i]){
        int to=poi[i];
        if(d[to]==d[x]+1&&(f=dfs(to,min(a,val[i])))>0)
            a-=f,F+=f,val[i]-=f,val[i^1]+=f;
        if(!a) break;
    }return F;
}
ll dinic(){ll re=0; while(bfs())re+=dfs(S,inf); return re;}
#define mid (l+r)/2
void Add(int &o,int p,int l,int r,int v){
    o=++u; if(p)link(o,p,inf);
    link(o,v,inf);//加入到包含a_v的区间
    if(l==r) return;
    if(A[v]<=mid) Add(lc[o],lc[p],l,mid,v),rc[o]=rc[p];
    else Add(rc[o],rc[p],mid+1,r,v),lc[o]=lc[p];
}
void Ask(int o,int l,int r,int x1,int x2,int v){
    if(!o) return ;
    if(x1<=l&&r<=x2) {link(v+n,o,inf); return;}
    if(x1<=mid) Ask(lc[o],l,mid,x1,x2,v);
    if(x2>mid) Ask(rc[o],mid+1,r,x1,x2,v);
}
int main(){
    scanf("%d",&n);
    S=n*2+1; T=S+1; u=T+1; 
    for(int i=1,B,W,P;i<=n;++i){
        scanf("%d%d%d%d%d%d",&A[i],&B,&W,&L[i],&R[i],&P);
        ans+=B+W; b[++m]=A[i]; b[++m]=L[i]; b[++m]=R[i];
        link(S,i,B); link(i,T,W); link(i,i+n,P);
    }sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1;//离散化
    for(int i=1;i<=n;++i){
        A[i]=lower_bound(b+1,b+m+1,A[i])-b;
        L[i]=lower_bound(b+1,b+m+1,L[i])-b;
        R[i]=lower_bound(b+1,b+m+1,R[i])-b;
        Ask(rt[i-1],1,m,L[i],R[i],i);
        Add(rt[i],rt[i-1],1,m,i);
    }printf("%lld",ans-dinic());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/kafuuchino/p/10808029.html
今日推荐