bzoj 3218 a + b Problem(最小割+主席树)

时间:2022-12-03 22:42:03

【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=3218

【题意】

给n个格子涂白或黑色,白则wi,黑则bi的好看度,若黑格i存在:

1<=j<I,li<=aj<=ri,格子为白色

则损失pi,问最大的好看度。

【思路】

考虑建立最小割模型:

  1. 首先将一个点拆成两个中间连pi
  2. 连边(S,Xi,wi) (Xi,T,bi)
  3. 对于一个满足i要求的j,连边(Xj,Yi,inf),代表i只有两种选择,一为设白色,一为损失pi。

  这样跑出的最小割即为答案。

  但该图的边数过多,因此需要优化。

  建一棵线段树,由线段树中所有被[li,ri]包含的点向Yi连边inf,由Xi向对应的叶子连边。然后加上j<i的条件,我们需要一棵可持久化线段树,因此需要Yi被T[i-1]的[li,ri]区间连边,Xi向T[i]的叶子连边。这样就成功将边数缩到O(nlogn)级别。

【代码】

 #include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define X(i) (i)
#define Y(i) (i+n)
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std; typedef long long ll;
const int N = 2e5+;
const int inf = 1e9; ll read() {
char c=getchar();
ll f=,x=;
while(!isdigit(c)) {
if(c=='-') f=-; c=getchar();
}
while(isdigit(c))
x=x*+c-'',c=getchar();
return x*f;
} struct Edge {
int u,v,cap,flow;
};
struct Dinic {
int d[N],cur[N],vis[N];
vector<Edge> es;
vector<int> g[N];
queue<int> q; void AddEdge (int u,int v,int w) {
es.push_back((Edge){u,v,w,});
es.push_back((Edge){v,u,,});
int m=es.size();
g[u].push_back(m-);
g[v].push_back(m-);
}
bool bfs(int s,int t) {
memset(vis,,sizeof(vis));
d[s]=; vis[s]=;
q.push(s);
while(!q.empty()) {
int u=q.front(); q.pop();
FOR(i,,(int)g[u].size()-) {
Edge& e=es[g[u][i]];
int v=e.v;
if(e.cap>e.flow&&!vis[v]) {
vis[v]=;
d[v]=d[u]+;
q.push(v);
}
}
}
return vis[t];
}
int dfs(int u,int a,int t) {
if(u==t||a==) return a;
int flow=,f;
for(int& i=cur[u];i<g[u].size();i++) {
Edge& e=es[g[u][i]];
int v=e.v;
if(d[v]==d[u]+&&(f=dfs(v,min(a,e.cap-e.flow),t))>) {
e.flow+=f;
es[g[u][i]^].flow-=f;
flow+=f,a-=f;
if(!a) break;
}
}
return flow;
}
int maxflow(int s,int t) {
int flow=;
while(bfs(s,t)) {
memset(cur,,sizeof(cur));
flow+=dfs(s,inf,t);
}
return flow;
}
} dc; int n,cnt; struct Tnode {
Tnode *ls,*rs;
int sum,id;
void * operator new (size_t,Tnode* l,Tnode* r) {
static Tnode mempool[N],*G=mempool;
G->ls=l,G->rs=r,G->id=++cnt;
return G++;
}
Tnode* build(int l,int r,int x,int from) {
int mid=l+r>>;
Tnode *t;
if(l==r)
t=new (0x0,0x0)Tnode;
else if(x<=mid)
t=new (ls->build(l,mid,x,from),rs) Tnode;
else
t=new (ls,rs->build(mid+,r,x,from)) Tnode;
dc.AddEdge(from,t->id,inf);
dc.AddEdge(id,t->id,inf);
return t;
}
void Add(int l,int r,int L,int R,int to) {
if(L<=l&&r<=R) {
dc.AddEdge(id,to,inf);
} else {
int mid=l+r>>;
if(L<=mid&&ls) ls->Add(l,mid,L,R,to);
if(mid<R&&rs) rs->Add(mid+,r,L,R,to);
}
} } *T[]; int hash[N],tot,a[N],b[N],l[N],r[N],p[N],w[N]; int main()
{
n=read();
cnt=Y(n);
int s=++cnt,t=++cnt;
T[]=new (0x0,0x0)Tnode;
T[]->ls=T[]->rs=T[];
ll ans=;
FOR(i,,n) {
a[i]=read(),b[i]=read(),w[i]=read(),l[i]=read(),r[i]=read(),p[i]=read();
hash[++tot]=a[i],hash[++tot]=l[i],hash[++tot]=r[i];
} sort(hash+,hash+tot+);
tot=unique(hash+,hash+tot+)-hash-;
FOR(i,,n) {
a[i]=lower_bound(hash+,hash+tot+,a[i])-hash;
l[i]=lower_bound(hash+,hash+tot+,l[i])-hash;
r[i]=lower_bound(hash+,hash+tot+,r[i])-hash;
} FOR(i,,n) {
ans+=w[i]+b[i];
dc.AddEdge(s,X(i),w[i]);
dc.AddEdge(X(i),t,b[i]);
T[i]=T[i-]->build(,tot,a[i],X(i));
T[i-]->Add(,tot,l[i],r[i],Y(i));
dc.AddEdge(Y(i),X(i),p[i]);
}
ans-=dc.maxflow(s,t);
printf("%lld\n",ans);
return ;
}

P.S.神的我无力吐槽=-=