卧薪尝胆,厚积薄发。
a+b Problem
Date: Mon Mar 25 09:18:51 CST 2019 In Category: NoCategory

Description:

$1\leqslant n\leqslant 5000$

Solution:

最小割比较容易看出来,划分到 $S$ 代表选黑色, $T$ 代表选白色,然后 $S$ 向每个点连染黑色的收益,每个点向 $T$ 连染白色的收益,代表如果割掉这条边会失去哪些,然后新建一个节点 $i'$ ,向满足那个条件的点连 $\infty$ 边, $i$ 向 $i'$ 连 $p_i$ 的边,代表如果存在一个这样的点是白色会失去这么多收益,最后用 $\sum b_i+\sum w_i-$ 最小割即可。
由于这样会建出 $O(n^2)$ 条边,那么发现限制条件实际上是一个二维偏序,因此用主席树优化连边即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cctype>
#include<cstring>
using namespace std;
inline int rd()
{
register int res = 0,f = 1;register char c = getchar();
while(!isdigit(c)){if(c == '-')f = -1;c = getchar();}
while(isdigit(c))res = (res << 1) + (res << 3) + c - '0',c = getchar();
return res * f;
}
int n;
#define MAXN 5010
int a[MAXN],b[MAXN],w[MAXN],l[MAXN],r[MAXN],p[MAXN];
int a_[MAXN],tot = 0;
namespace DINIC
{
#define MAXP (MAXN * 30)
#define MAXE (MAXN * 100)
struct edge
{
int to,nxt;
int f;
}e[MAXE << 1];
int edgenum = 0;
int lin[MAXP] = {0};
void add(int a,int b,int f)
{//cout << a << " " << b << " " << f << endl;
e[edgenum] = (edge){b,lin[a],f};lin[a] = edgenum++;
e[edgenum] = (edge){a,lin[b],0};lin[b] = edgenum++;
return;
}
int S,T;
#define INF 0x3f3f3f3f
int ch[MAXP];
bool BFS()
{
memset(ch,-1,sizeof(ch));ch[S] = 0;
queue<int> q;q.push(S);
while(!q.empty())
{
int k = q.front();q.pop();
for(int i = lin[k];i != -1;i = e[i].nxt)
{
if(ch[e[i].to] == -1 && e[i].f)
{
ch[e[i].to] = ch[k] + 1;
q.push(e[i].to);
}
}
}
return (ch[T] != -1);
}
int flow(int k,int f)
{
if(k == T)return f;
int r = 0;
for(int i = lin[k];i != -1 && f > r;i = e[i].nxt)
{
if(ch[e[i].to] == ch[k] + 1 && e[i].f)
{
int l = flow(e[i].to,min(e[i].f,f - r));
e[i].f -= l;r += l;e[i ^ 1].f += l;
}
}
if(r == 0)ch[k] = -1;
return r;
}
int dinic()
{
int ans = 0,r;
while(BFS())while(r = flow(S,INF))ans += r;
return ans;
}
}
struct node
{
int lc,rc;
}t[MAXN * 30];
int ptr = 0;
int newnode(){return ++ptr;}
int root[MAXN];
#define mid ((l + r) >> 1)
void insert(int &rt,int id,int p,int l,int r)
{
int k = newnode();t[k] = t[rt];DINIC::add(k,rt,INF);rt = k;
if(l == r){DINIC::add(rt,id,INF);return;}
if(p <= mid)
{
insert(t[rt].lc,id,p,l,mid);DINIC::add(rt,t[rt].lc,INF);
}
else
{
insert(t[rt].rc,id,p,mid + 1,r);DINIC::add(rt,t[rt].rc,INF);
}
return;
}
void add(int rt,int id,int L,int R,int l,int r)
{
if(rt == 0)return;
if(L <= l && r <= R){DINIC::add(id,rt,INF);return;}
if(L <= mid)add(t[rt].lc,id,L,R,l,mid);
if(R > mid)add(t[rt].rc,id,L,R,mid + 1,r);
return;
}
int main()
{
memset(DINIC::lin,-1,sizeof(DINIC::lin));
scanf("%d",&n);
int sum = 0;
for(int i = 1;i <= n;++i)
{
a[i] = rd();b[i] = rd();w[i] = rd();
l[i] = rd();r[i] = rd();p[i] = rd();
sum += b[i] + w[i];
a_[i] = a[i];
}
sort(a_ + 1,a_ + 1 + n);
tot = unique(a_ + 1,a_ + 1 + n) - a_ - 1;
a_[++tot] = INF;
for(int i = 1;i <= n;++i)
{
a[i] = lower_bound(a_ + 1,a_ + 1 + tot,a[i]) - a_;
l[i] = lower_bound(a_ + 1,a_ + 1 + tot,l[i]) - a_;
r[i] = upper_bound(a_ + 1,a_ + 1 + tot,r[i]) - a_ - 1;
}
ptr = 2 * n + 2;
DINIC::S = 2 * n + 1;DINIC::T = 2 * n + 2;
--tot;
for(int i = 1;i <= n;++i)
{
root[i] = root[i - 1];
insert(root[i],i,a[i],1,tot);
DINIC::add(i,i + n,p[i]);
add(root[i - 1],i + n,l[i],r[i],1,tot);
DINIC::add(DINIC::S,i,b[i]);
DINIC::add(i,DINIC::T,w[i]);
}
cout << sum - DINIC::dinic() << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡