[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的主要内容,如果未能解决你的问题,请参考以下文章