[BZOJ3218]a + b Problem

Posted jefflyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3218]a + b Problem相关的知识,希望对你有一定的参考价值。

$\\newcommand{\\edge}[1]{\\mathop\\rightarrow\\limits^{#1}}$先取所有$b_i,w_i$,然后建图跑最小割

要么割$w_i$要么割$b_i$,所以这两条边必须相连,初步的想法是这样:

技术分享图片

如果割了$w_i$并且存在题目所说的$j$,那么我们还要割掉$p_i$,所以不妨拆点,构造一条$j\\edge{\\infty}i‘\\edge{p_i}i\\edge{b_i}T$的路径,不难发现如果割掉了$w_i$则必然割掉$p_i$

技术分享图片

直接建图,边数是$O(n^2)$的,空间太大,所以要优化建图

约束是$a_j\\in[l_i,r_i]$的形式,我们可以建一棵线段树,儿子向父亲连边,把$j$连到线段树中对应下标的叶子节点,并且把$[l_i,r_i]$这个区间在线段树中的对应节点连向$i‘$就可以了

这样做并没有考虑$j\\lt i$这个约束,把线段树可持久化就可以加上这个约束了,对应的连边也要“可持久化”,即加入指向新节点的边,本来对于新建的链,原线段树中与这条链重复的所有节点都要向新节点连边,但因为我们在新链上自底向上连边,所以只需把原来的叶子节点连到新的叶子节点即可

#include<stdio.h>
#include<string.h>
#include<map>
using namespace std;
const int inf=2147483647;
int h[200010],cur[200010],nex[1000010],to[1000010],cap[1000010],dis[200010],q[1000010],M=1,S,T;
void add(int a,int b,int c){
	M++;
	to[M]=b;
	cap[M]=c;
	nex[M]=h[a];
	h[a]=M;
	M++;
	to[M]=a;
	cap[M]=0;
	nex[M]=h[b];
	h[b]=M;
}
bool bfs(){
	int head,tail,x,i;
	memset(dis,-1,sizeof(dis));
	head=tail=1;
	q[1]=S;
	dis[S]=0;
	while(head<=tail){
		x=q[head];
		head++;
		for(i=h[x];i;i=nex[i]){
			if(cap[i]&&dis[to[i]]==-1){
				dis[to[i]]=dis[x]+1;
				if(to[i]==T)return 1;
				tail++;
				q[tail]=to[i];
			}
		}
	}
	return 0;
}
int dfs(int x,int flow){
	if(x==T)return flow;
	int i,f;
	for(i=cur[x];i;i=nex[i]){
		if(cap[i]&&dis[to[i]]==dis[x]+1){
			f=dfs(to[i],min(flow,cap[i]));
			if(f){
				cap[i]-=f;
				cap[i^1]+=f;
				if(cap[i])cur[x]=i;
				return f;
			}
		}
	}
	dis[x]=-1;
	return 0;
}
int dicnic(){
	int ans=0,tmp;
	while(bfs()){
		memcpy(cur,h,sizeof(h));
		while(tmp=dfs(S,inf))ans+=tmp;
	}
	return ans;
}
struct seg{
	int l,r;
}t[1000010];
int C,n;
int tr(int x){return x+2*(n+1);}
void insert(int&nr,int pr,int p,int v,int l,int r){
	nr=++C;
	t[nr]=t[pr];
	if(l==r){
		if(pr)add(tr(pr),tr(nr),inf);
		return add(v,tr(nr),inf);
	}
	int mid=(l+r)>>1;
	if(p<=mid)
		insert(t[nr].l,t[pr].l,p,v,l,mid);
	else
		insert(t[nr].r,t[pr].r,p,v,mid+1,r);
	if(t[nr].l)add(tr(t[nr].l),tr(nr),inf);
	if(t[nr].r)add(tr(t[nr].r),tr(nr),inf);
}
void modify(int L,int R,int v,int l,int r,int x){
	if(x==0)return;
	if(L<=l&&r<=R)return add(tr(x),v,inf);
	int mid=(l+r)>>1;
	if(L<=mid)modify(L,R,v,l,mid,t[x].l);
	if(mid<R)modify(L,R,v,mid+1,r,t[x].r);
}
map<int,int>pos;
map<int,int>::iterator it;
int a[5010],l[5010],r[5010],rt[5010];
int main(){
	int N,i,b,w,p,s;
	scanf("%d",&n);
	S=n*2+1;
	T=n*2+2;
	s=0;
	for(i=1;i<=n;i++){
		scanf("%d%d%d%d%d%d",a+i,&b,&w,l+i,r+i,&p);
		s+=b+w;
		add(S,i,w);
		add(i,T,b);
		add(i+n,i,p);
		pos[a[i]]=pos[l[i]]=pos[r[i]]=1;
	}
	N=0;
	for(it=pos.begin();it!=pos.end();it++)it->second=++N;
	for(i=1;i<=n;i++){
		modify(pos[l[i]],pos[r[i]],i+n,1,N,rt[i-1]);
		insert(rt[i],rt[i-1],pos[a[i]],i,1,N);
	}
	printf("%d",s-dicnic());
}

以上是关于[BZOJ3218]a + b Problem的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3218 a + b Problem

[BZOJ3218]a + b Problem

「bzoj 3218」 a + b Problem

BZOJ 3218 a + b Problem

bzoj 3218: a + b Problem

BZOJ 3218 A+B Problem(最大流 + 主席树优化建图)