「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
",sum-Dinic());
}
原文地址:https://www.cnblogs.com/hbxblog/p/10308870.html