zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Hadoop概论
    虚拟机
    Linux的常用命令
    jsoup抓取数据
    分享JQuery动画插件Velocity.js的六种列表加载特效
    html5和css3打造一款创意404页面
    分享一款基于jquery的圆形动画按钮
    一款基于jquery和css3实现的摩天轮式分享按钮
    一款纯css3实现的环形导航菜单
    一款纯css3实现的动画加载导航
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10808029.html
Copyright © 2011-2022 走看看