[BZOJ3218]a + b Problem-[主席树+网络流-最小割]

Description

传送门

Solution

此处我们按最小割的思路考虑。

暴力:S->i表示该点选黑色的权值b[i];i->T表示该点选白色的权值w[i]。考虑如果某个点i受点j为白点的影响,则将点i连向点j,边权为p[i]。但这么做假如有多个点j,p[i]就会被算多次。可以将i点拆为i和i'。则将i'连向j,边权为inf(即该边不能割),将i连向i',边权为p[i]。

不过这么搞肯定要爆。考虑一下怎么优化。

我们发现最耗空间的是i'->j的边。(如果l[i],r[i]给的范围大的话空间简直。。em)。然后由于是点->区间,考虑线段树一类的知识点。显然主席树是可以的。

主席树下标按照a的大小。

我们从左到右把点i加进去(a[i],l[i],r[i]要离散化),在主席树里找区间[l[i],r[i]]直接连边;然后将i点连向主席树内所有(存储区间包含a[i]的)节点。因为可能在主席树的某个节点下挂了一堆的点(即很多点i的a[i]相等),我们将主席树新建的节点向之前的节点连边。

由于各个点i已经向所有包含它们的主席树节点连边,主席树的节点间无需再连边了。

主席树相关的各种边边权都为inf。

然后就ok啦啦啦。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int inf=1e9;
int n,m,k;
 
int h[500010],tot;
struct pas{int x,y,nxt,w,op,cost;}g[1000100];
int dep[500020],S,T;
queue<int>q;
struct DINIC{
bool bfs()
{
    int x;
    memset(dep,0,sizeof(dep));dep[S]=1;
    while (!q.empty()) q.pop();
    q.push(S);
    while (!q.empty())
    {
        x=q.front();q.pop();
        for (int i=h[x];i;i=g[i].nxt)
        if (!dep[g[i].y]&&g[i].w)
        {
            dep[g[i].y]=dep[x]+1;
            q.push(g[i].y);
            if (g[i].y==T) return 1;
        }
    }
    return 0;
}
int dfs(int x,int flow)
{
    if (x==T||(!flow))return flow;
    int temp=0,js;
    for (int i=h[x];i;i=g[i].nxt)
    if (dep[g[i].y]==dep[x]+1&&g[i].w)
    {
        js=dfs(g[i].y,min(flow,g[i].w));
        if (js)
        {
            g[i].w-=js;
            g[g[i].op].w+=js;
            temp+=js;
            flow-=js;
            if (!flow) return temp;
        }
    }
    if (!temp) dep[x]=0;
    return temp;
}
    int dinic()
    {
        int ans=0;
        while (bfs()) 
        ans+=dfs(S,inf);
        return ans;
    } 
 }D;
  
void add(int x,int y,int w)
{
    g[++tot].x=x;g[tot].y=y;g[tot].w=w;g[tot].nxt=h[x];g[tot].op=tot+1;h[x]=tot;
    g[++tot].x=y;g[tot].y=x;g[tot].w=0;g[tot].nxt=h[y];g[tot].op=tot-1;h[y]=tot;
}
 
int a[5010],b[5010],w[5010],l[5010],r[5010],p[5010],hehe[5010];
int lc[500010],rc[500010],cnt,rt;
void query(int k,int l,int r,int askx,int asky,int p)
{
    if (!k) return;
    if (askx<=l&&r<=asky) 
    {
        add(p,k,inf);
        return;
    }
    int mid=(l+r)/2;if (askx<=mid) query(lc[k],l,mid,askx,asky,p);
    if (asky>mid) query(rc[k],mid+1,r,askx,asky,p);
}
int modify(int k,int l,int r,int id,int x)
{
    int o=++cnt;lc[o]=lc[k];rc[o]=rc[k];
    if (k) add(o,k,inf);
    add(o,x,inf);
    if (l==r) return o;
    int mid=(l+r)/2;
    if (id<=mid) lc[o]=modify(lc[o],l,mid,id,x);else rc[o]=modify(rc[o],mid+1,r,id,x);
    return o;
}
int sum=0;
int main()
{
    scanf("%d",&n);cnt=2*n+1;
    S=0;T=2*n+1;
    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]);
        sum+=w[i]+b[i];
        hehe[i]=a[i];
        add(S,i,b[i]);add(i,T,w[i]);add(i,n+i,p[i]);
    }
    sort(hehe+1,hehe+n+1);
    for (int i=1;i<=n;i++)
    {
        a[i]=lower_bound(hehe+1,hehe+n+1,a[i])-hehe;
        l[i]=lower_bound(hehe+1,hehe+n+1,l[i])-hehe;
        r[i]=upper_bound(hehe+1,hehe+n+1,r[i])-hehe-1;
        if (l[i]<=r[i]) query(rt,1,n,l[i],r[i],n+i);
        rt=modify(rt,1,n,a[i],i);
    }
    cout<<sum-D.dinic();
}

猜你喜欢

转载自www.cnblogs.com/coco-night/p/9559484.html