「BZOJ 3218」 a + b Problem

题目链接

戳我

\(Solution\)

题目为什么是\(a\ +\ b\ Problem\)啊?这和题面半毛钱关系都没有。
现在来讲一下这题的解法吧,我们首先看看没有奇怪的方格这一个条件吧.

其实没有这个条件还是很简单的,就只要将每个点连向原点表示选流量为\(B\)表示选黑色的,在将这个点连向汇点流量为\(W\)表示选白色的,跑一遍最小割就好了

现在来看看有奇怪的方格这一个条件吧,我们可以对于每个节点\(i\)新建一个节点\(i'\),我们将每个\(i\)连向\(i'\)流量为\(P\),在对于满足奇怪方格限制的\(j\),将\(i'\)\(j\)连一条流量为\(inf\)的边再跑最小割就好了

但是这一题明显不是这么简单就好了,观察数据范围,发现这\(n^2\)的连边是过不去的.所以我们应该想想优化,至于怎么优化用一个主席树就好了.

\(Code\)

#include<bits/stdc++.h> 
#define inf 1e9
using namespace std;
typedef long long ll;
int read(){
    int x=0,f=1; char c=getchar();
    while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
struct node{
    int to,next,v;
}a[1000010];
int head[500010],cnt,n,m,s,t,x,y,z,dep[85010];
void add(int x,int y,int c){
    a[++cnt].to=y,a[cnt].next=head[x],a[cnt].v=c,head[x]=cnt;
    a[++cnt].to=x,a[cnt].next=head[y],a[cnt].v=0,head[y]=cnt;
}
queue<int> q;
int bfs(){
    memset(dep,0,sizeof(dep));
    q.push(s),dep[s]=1;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=a[i].next){
            int v=a[i].to;
            if(!dep[v]&&a[i].v>0)
                dep[v]=dep[now]+1,q.push(v);
        }
    }
    if(dep[t])
        return 1;
    return 0;
}
int dfs(int k,int list){
    if(k==t||!list)
        return list;
    for(int i=head[k];i;i=a[i].next){
        int v=a[i].to;
        if(dep[v]==dep[k]+1&&a[i].v>0){
            int p=dfs(v,min(list,a[i].v));
            if(p){
                a[i].v-=p;
                if(i&1) a[i+1].v+=p;
                else a[i-1].v+=p;
                return p;
            }
        }
    }
    dep[k]=0;
    return 0;
}
int Dinic(){
    int ans=0,k;
    while(bfs()){
        while((k=dfs(s,inf)))
            ans+=k;
    }
    return ans;
}
struct node1{
    int l,r;
}tree[1000010];
int tot,goal;
void update(int &k,int f,int l,int r,int c){
    k=++tot;
    tree[k]=tree[f];
    if(l==r){
        add(k+t,goal,inf);
        if(f) add(k+t,f+t,inf);
        return ;
    }
    int mid=(l+r)>>1;
    if(c<=mid) update(tree[k].l,tree[f].l,l,mid,c);
    else update(tree[k].r,tree[f].r,mid+1,r,c);
    if(tree[k].l) add(k+t,tree[k].l+t,inf);
    if(tree[k].r) add(k+t,tree[k].r+t,inf);
}
void insert(int k,int l,int r,int L,int R) {
    if(L>r||l>R) return;
    if(L<=l&&r<=R) {
        add(n+goal,t+k,inf);
        return;
    }
    int mid=(l+r)>>1;
    if(tree[k].l) insert(tree[k].l, l, mid, L,R);
    if(tree[k].r) insert(tree[k].r, mid+1,r,L,R);
}
int A[5011],B,W,L[5011],R[5011],P,sum,o[100010];
int len,rt,p;
main(){
    n=read(),s=0,t=n*2+1;
    for(int i=1;i<=n;i++){
        A[i]=read(),B=read(),W=read(),L[i]=read(),R[i]=read(),P=read(),sum+=B+W;
        add(s,i,B),add(i,t,W),add(i,i+n,P),o[++len]=A[i],o[++len]=L[i],o[++len]=R[i];
    }
    sort(o+1,o+len+1);
    len=unique(o+1,o+len+1)-o-1;
    for (int i=1;i<=n;++i){
        goal=i;
        A[i]=lower_bound(o+1,o+len+1,A[i])-o;
        L[i]=lower_bound(o+1,o+len+1,L[i])-o;
        R[i]=lower_bound(o+1,o+len+1,R[i])-o;
        insert(p,1,len,L[i],R[i]);
        update(rt,p,1,len,A[i]);
        p=rt;
    }
    printf("%d\n",sum-Dinic());
}

猜你喜欢

转载自www.cnblogs.com/hbxblog/p/10308870.html