【bzoj3218】a + b Problem 【网络流】【最小割】【主席树】
题目传送门
题解:
考虑一种朴素的连边:
然后用减去最小割就是答案。
但是这样连边有级别的边数,,显然不行。
于是我们就有了一些神奇的操作:主席树优化连边!
先把a,l,r进行一波离散化。
连边方法:
主席树上,儿子向父亲连边,容量inf。
当要创建一个新版本时,上一个版本原来位置的节点向新增的个相同位置的节点连边,容量。新增的节点向其父亲连边,容量。在线段树上对应的叶子节点连边。
然后第个版本中在树上对应的一堆区间节点向连边,容量。
详细解释可以去看PoPoQQQ神犇的博客!
吐槽:为什么我的常数那么大!为什么我的代码那么矬!
UPD:网络流模板有问题,work数组简直就是害人的!增加运行时间的利器!
代码:
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5005,M=1200005,inf=0x7fffffff;
int n,tot=1,a[N],b[N],w[N],l[N],r[N],p[N],Hash[N];
int cnt=1,s=0,t=1,root[N],head[M],work[M],to[M],nxt[M],dd[M],dep[M],ch[M][2];
ll ans;
queue<int> q;
void adde(int u,int v,int d){
to[++cnt]=v;
nxt[cnt]=head[u];
dd[cnt]=d;
head[u]=cnt;
to[++cnt]=u;
nxt[cnt]=head[v];
dd[cnt]=0;
head[v]=cnt;
}
void build(int &x,int l,int r){
x=++tot;
if(l==r){
return;
}
int mid=(l+r)/2;
adde(tot+1,x,inf);
build(ch[x][0],l,mid);
adde(tot+1,x,inf);
build(ch[x][1],mid+1,r);
}
void update(int y,int &x,int l,int r,int k,int node){
x=++tot;
ch[x][0]=ch[y][0];
ch[x][1]=ch[y][1];
adde(y,x,inf);
if(l==r){
adde(node,x,inf);
return;
}
int mid=(l+r)/2;
adde(tot+1,x,inf);
if(k<=mid){
update(ch[y][0],ch[x][0],l,mid,k,node);
}else{
update(ch[y][1],ch[x][1],mid+1,r,k,node);
}
}
void get(int x,int l,int r,int L,int R,int nnode){
if(L<=l&&R>=r){
adde(x,nnode,inf);
return;
}
int mid=(l+r)/2;
if(L<=mid){
get(ch[x][0],l,mid,L,R,nnode);
}
if(R>mid){
get(ch[x][1],mid+1,r,L,R,nnode);
}
}
bool bfs(){
memset(dep,0,sizeof(int)*(tot+1));
while(!q.empty()){
q.pop();
}
dep[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front(),v;
q.pop();
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(dd[i]&&!dep[v]){
dep[v]=dep[u]+1;
if(v==t){
return true;
}
q.push(v);
}
}
}
return false;
}
ll dfs(int u,int f){
if(u==t){
return f;
}
int v;
ll res=0,tmp;
for(int &i=work[u];i&&f;i=nxt[i]){
v=to[i];
if(dd[i]&&dep[v]==dep[u]+1&&(tmp=dfs(v,min(f,dd[i])))){
dd[i]-=tmp;
dd[i^1]+=tmp;
f-=tmp;
res+=tmp;
}
}
if(!res){
dep[u]=0;
}
return res;
}
ll maxflow(){
ll res=0;
while(bfs()){
memcpy(work,head,sizeof(int)*(tot+1));
res+=dfs(s,0x7fffffff);
}
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d%d%d%d",&a[i],&b[i],&w[i],&l[i],&r[i],&p[i]);
Hash[++Hash[0]]=a[i];
ans+=b[i]+w[i];
}
Hash[++Hash[0]]=inf;
sort(Hash+1,Hash+Hash[0]+1);
Hash[0]=unique(Hash+1,Hash+Hash[0]+1)-Hash-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(Hash+1,Hash+Hash[0]+1,a[i])-Hash;
l[i]=lower_bound(Hash+1,Hash+Hash[0]+1,l[i])-Hash;
r[i]=upper_bound(Hash+1,Hash+Hash[0]+1,r[i])-Hash-1;
}
build(root[0],1,Hash[0]);
for(int i=1;i<=n;i++){
int node=++tot,nnode=++tot;
adde(s,node,w[i]);
adde(node,t,b[i]);
adde(nnode,node,p[i]);
update(root[i-1],root[i],1,Hash[0],a[i],node);
if(l[i]<=r[i]){
get(root[i-1],1,Hash[0],l[i],r[i],nnode);
}
}
printf("%lld\n",ans-maxflow());
return 0;
}