[BZOJ3218]a + b Problem
description
sol
最小鸽建图。
假设\(S\)集合是染黑色,\(T\)集合是染白色。
那么从\(S\)向\(i\)连\(b_i\)边,从\(i\)向\(T\)连\(w_i\)边。
每个点\(i\)多拆出一个点\(i'\),从\(i\)向\(i'\)连\(p_i\)边。对于所有满足\(1\le j<i\)且\(l_i\le a_j\le r_i\)的\(j\),从\(i'\)向\(j\)连\(inf\)边。
然后跑最小鸽就好了。
然鹅。这样建图的边数是\(O(n^2)\)级别的。
所以肯定是过不去的。
考虑优化。
发现条件其实是一个二位偏序的形式,所以可以用主席树优化建边。
具体来说,以\(a\)值作为主席树下标,每个\(i'\)向主席树上的\(\log n\)个区间连边,每个区间向其中包含的所有\(i\)连边,容量都是\(inf\)。
这样点数和边数都是\(O(n\log n)\)级别的,就可以通过本题了。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 5e5+5;
const int inf = 1e9;
struct president_tree{int ls,rs;}t[N<<2];
struct edge{int to,nxt,w;}a[N];
int n,A[N],l[N],r[N],o[N],len,S,T,tot,head[N],cnt=1,dep[N],cur[N],rt,goal,ans;
queue<int>Q;
void link(int u,int v,int w){
a[++cnt]=(edge){v,head[u],w};head[u]=cnt;
a[++cnt]=(edge){u,head[v],0};head[v]=cnt;
}
bool bfs(){
memset(dep,0,sizeof(dep));
dep[S]=1;Q.push(S);
while (!Q.empty()){
int u=Q.front();Q.pop();
for (int e=head[u];e;e=a[e].nxt)
if (a[e].w&&!dep[a[e].to])
dep[a[e].to]=dep[u]+1,Q.push(a[e].to);
}
return dep[T];
}
int dfs(int u,int f){
if (u==T) return f;
for (int &e=cur[u];e;e=a[e].nxt)
if (a[e].w&&dep[a[e].to]==dep[u]+1){
int tmp=dfs(a[e].to,min(a[e].w,f));
if (tmp) {a[e].w-=tmp;a[e^1].w+=tmp;return tmp;}
}
return 0;
}
int dinic(){
int res=0;
while (bfs()){
for (int i=1;i<=tot;++i) cur[i]=head[i];
while (int tmp=dfs(S,inf)) res+=tmp;
}
return res;
}
void query(int x,int l,int r,int ql,int qr){
if (l>=ql&&r<=qr) {link(goal,x,inf);return;}
int mid=l+r>>1;
if (ql<=mid) query(t[x].ls,l,mid,ql,qr);
if (qr>mid) query(t[x].rs,mid+1,r,ql,qr);
}
void modify(int &x,int l,int r,int p){
t[++tot]=t[x];link(tot,x,inf);x=tot;
link(x,goal,inf);
if (l==r) return;int mid=l+r>>1;
if (p<=mid) modify(t[x].ls,l,mid,p);else modify(t[x].rs,mid+1,r,p);
}
int main(){
n=gi();S=2*n+1;T=tot=2*n+2;
for (int i=1,b,w,p;i<=n;++i){
A[i]=gi(),b=gi(),w=gi(),ans+=b+w;
l[i]=gi(),r[i]=gi(),p=gi();
link(S,i,b),link(i,T,w);
link(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){
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;
goal=n+i,query(rt,1,len,l[i],r[i]);
goal=i,modify(rt,1,len,A[i]);
}
printf("%d\n",ans-dinic());
return 0;
}