[bzoj3218][网络流-最小割][线段树优化建图]a + b Problem

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82261923

题目传送门

题解

显然最小割 S->i连边
边权w[i] i->T连边 边权b[i]
拆点i’表示是奇怪的点时 i’->i连边 边权p[i]
枚举 1 <= j < i ,要求 l [ i ] <= a [ j ] <= r [ i ] ,连边j->i’ 边权INF 这样时空都是 n 2

考虑优化
发现连的点都在一段区间内
维护一个可持久化线段树,树上儿子节点向父亲节点连边 边权INF
叶子节点,设这个叶子节点的值域为[ a i , a i ],那么i->该节点连边 边权INF
裸跑最小割即可
我怎么跑的这么慢啊懒得优化了就这样吧。。
upd:
早上起床想起来怎么优化了。。
你把a,l,r全部离散化一下就行了..
懒癌晚期还是不想打

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 1<<31-1
using namespace std;
queue<int> li;
struct dinic{int x,y,c,next;}a[1510000];int len,last[210000];
void ins(int x,int y,int c)
{
    len++;
    a[len].x=x;a[len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
    len++;
    a[len].x=y;a[len].y=x;a[len].c=0;
    a[len].next=last[y];last[y]=len;
}
int h[210000],st,ed,n;
bool bt_h()
{
    memset(h,0,sizeof(h));h[st]=1;
    li.push(st);
    while(!li.empty())
    {
        int x=li.front();
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(!h[y]&&a[k].c)h[y]=h[x]+1,li.push(y);
        }
        li.pop();
    }
    return h[ed]>0;
}
int cur[210000];
int findflow(int x,int f)
{
    if(x==ed)return f;
    int s=0,t;
    for(int k=cur[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(h[y]==h[x]+1&&a[k].c&&s<f)
        {
            s+=(t=findflow(y,min(a[k].c,f-s)));
            a[k].c-=t;a[k^1].c+=t;
            if(a[k].c)cur[x]=k;
            if(s==f)break;
        }
    }
    if(s==0)h[x]=0;
    return s;
}
//-------dinic-------
struct segtree{int lc,rc,gg;}tr[6005*30+5];int trlen;
void add(int &now,int l,int r,int p,int op)
{
    if(!now)now=++trlen;
    tr[now].gg=trlen;
    if(l==r)
    {
        ins(op,tr[now].gg+2*n,inf);
        return ;
    }
    int mid=(l+r)/2;
    if(p<=mid)add(tr[now].lc,l,mid,p,op),ins(tr[tr[now].lc].gg+2*n,tr[now].gg+2*n,inf);
    else add(tr[now].rc,mid+1,r,p,op),ins(tr[tr[now].rc].gg+2*n,tr[now].gg+2*n,inf);
}
void meg(int &x,int y,int la)
{
    if(x==0)
    {
        if(la&&y)ins(tr[y].gg+2*n,tr[la].gg+2*n,inf);
        x=y;
        return ;
    }
    if(y==0)return;
    ins(tr[y].gg+2*n,tr[x].gg+2*n,inf);
    meg(tr[x].lc,tr[y].lc,x);
    meg(tr[x].rc,tr[y].rc,x);
}
void insert(int now,int l,int r,int ql,int qr,int op)
{
    if(!now)return ;
    if(l==ql&&r==qr){ins(tr[now].gg+2*n,op,inf);return ;}
    int lc=tr[now].lc,rc=tr[now].rc;
    int mid=(l+r)/2;
    if(qr<=mid)insert(lc,l,mid,ql,qr,op);
    else if(mid+1<=ql)insert(rc,mid+1,r,ql,qr,op);
    else insert(lc,l,mid,ql,mid,op),insert(rc,mid+1,r,mid+1,qr,op);
}
int rt[5005],w[5005],b[5005];
int aa[5005];
int main()
{
//  freopen("b.in","r",stdin);
//  freopen("b.out","w",stdout);
    scanf("%d",&n);
//  int ans=0;len=1;
    /*for(int i=1;i<=n;i++)
    {
        int l,r,p;scanf("%d%d%d%d%d%d",&aa[i],&b[i],&w[i],&l,&r,&p);
        ans=ans+b[i]+w[i];
        ins(i+n,i,p);
        for(int j=1;j<i;j++)if(aa[j]>=l&&aa[j]<=r)ins(j,i+n,inf);
    }*/
    int ans=0;len=1;
    for(int i=1;i<=n;i++)
    {
        int a,l,r,p;
        scanf("%d%d%d%d%d%d",&a,&b[i],&w[i],&l,&r,&p);
        ans=ans+b[i]+w[i];
        ins(i+n,i,p);
        insert(rt[i-1],0,1000000000,l,r,i+n);
        add(rt[i],0,1000000000,a,i);
        meg(rt[i],rt[i-1],0);
    }
//  printf("%d\n",len);
    st=trlen+2*n+1;ed=st+1;
    for(int i=1;i<=n;i++)ins(st,i,w[i]),ins(i,ed,b[i]);
    int sum=0;
    while(bt_h())
    {
        for(int i=1;i<=ed;i++)cur[i]=last[i];
        sum+=findflow(st,inf);
    }
    printf("%d\n",ans-sum);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82261923