题目传送门
题解
这题简直丧心病狂,调了一天都没发现自己错在哪。
首先是一个很显然的最小割,见下图。
别问我为什么画的这么丑,我…
注意网络中的边都是单向边,边的方向很重要。
与s相连代表选黑色,反之选白色。对于每个点i建出虚点i’然后对于会使i变的奇♂怪的j,由i’向j连边,容量为INF,代表如果i黑j白就要割掉pi。
直接跑最小割肯定超时超内存,因为i’->j的边太多了,可能有n^2条。
我们考虑用一种数据结构优化连边。我们发现,对于能使i变得奇♂怪的j,a[j]都在一段连续的区间里。于是我们可以用线段树来优化。建出线段树,对于一个i对应的l[i]到r[i],直接把它分为最多logn个子区间,然后i’向线段树上对应区间的点连边,j直接连向叶子节点。线段树上父亲向儿子连边。容量均为INF。
这样边数就优化到了nlogn条。等等j < <script type="math/tex" id="MathJax-Element-261"><</script>i呢?我们对于i’的连边只能包含其之前的j!我们将线段树可持久化掉就行了。连边向前一个版本的线段树连。
这里说一下做这题的心路历程。第一遍写完S,T集合搞反了,样例不过。样例过了后持续一天60-70-90的得分。
UOJ上交了几十次的那个SB就是我
首先,建出新的一条链时,要向旧版本的节点连边。因为我们复制的只是信息,连边没有复制,所以对于a相同的情况如果不连就会错(70分原因)。或者一开始离散化时将相同的a强行改不同。
然后对于线段树上的点要有一个在网络上的标号,我发现直接标号跟root-Tree+tot不同。原因是指针太乱我写错了,指针真TM容易错啊!(话说为什么我要用指针啊)
此时仍旧TLE一个点,没错加上离散化才能过。更可怕的是UOJ过了BZOJ超时,没错我空间开太多了!为什么是空间?我怎么知道,空间改小一点才AC。
这可真是一道令人心情愉悦可以延绵益寿的好题啊!
代码
#include <bits/stdc++.h>
#define N 5005
#define maxn 100010
#define maxm 1000010
#define INF 0x7FFFFFFF
using namespace std;
int n, cur = -1, cnt, tot, Sum, MAX, s, t;
int level[maxn], q[maxn];
struct Save{
int val, id;
bool operator < (const Save& OTHER) const{
return val < OTHER.val;
}
}Num[maxn];
struct Data{
int a, b, w, l, r, p;
}bl[maxn];
struct Tnode{
Tnode *lson, *rson;
int id;
}Tree[maxn], *Root[maxn];
struct List{
List *next, *rev;
int obj, cap;
}Edg[maxm], *head[maxn], *iter[maxn];
inline void Addedge(int a, int b, int c){
Edg[++cur].next = head[a]; Edg[cur].obj = b; Edg[cur].cap = c; Edg[cur].rev = Edg+(cur^1); head[a] = Edg+cur;
Edg[++cur].next = head[b]; Edg[cur].obj = a; Edg[cur].cap = 0; Edg[cur].rev = Edg+(cur^1); head[b] = Edg+cur;
}
inline bool bfs(){
int hh = 0, tt = 0;
q[hh] = s;
memset(level, -1, sizeof(level));
level[s] = 0;
while(hh <= tt){
int now = q[hh++];
for(List *p = head[now]; p; p = p->next){
int v = p->obj, c = p->cap;
if(c && level[v] == -1){
level[v] = level[now] + 1;
q[++tt] = v;
}
}
}
return level[t] != -1;
}
int Dinic(int now, int f){
if(now == t || !f) return f;
int ret = 0;
for(List *&p = iter[now]; p; p = p->next){
int v = p->obj, c = p->cap;
if(c && level[v] == level[now] + 1){
int d = Dinic(v, min(c, f));
ret += d;
f -= d;
p->cap -= d;
p->rev->cap += d;
if(!f) break;
}
}
return ret;
}
inline int MinCut(){
int flow = 0;
while(bfs()){
memcpy(iter, head, sizeof(iter));
flow += Dinic(s, INF);
}
return flow;
}
inline Tnode *NewTnode(){
Tree[cnt].lson = Tree[cnt].rson = Tree;
return Tree+cnt++;
}
void Update(Tnode *root, int L, int R, int x, int y){
if(L == R){
Addedge(root->id, y, INF);
return;
}
int mid = (L + R) >> 1;
Tnode *p = NewTnode();
if(x <= mid){
*p = *root->lson; root->lson = p;
Addedge(++tot, p->id, INF);
root->lson->id = tot;
Update(root->lson, L, mid, x, y);
}
else{
*p = *root->rson; root->rson = p;
Addedge(++tot, p->id, INF);
root->rson->id = tot;
Update(root->rson, mid+1, R, x, y);
}
if(root->lson != Tree) Addedge(root->id, root->lson->id, INF);
if(root->rson != Tree) Addedge(root->id, root->rson->id, INF);
}
void Dfs(Tnode *root, int L, int R, int x, int y, int p){
if(root == Tree || x > R || y < L) return;
if(x <= L && y >= R){
Addedge(p, root->id, INF);
return;
}
int mid = (L + R) >> 1;
Dfs(root->lson, L, mid, x, y, p);
Dfs(root->rson, mid+1, R, x, y, p);
}
inline int Read(){
int x = 0; char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
void Print(int x){
if(x > 9) Print(x / 10);
putchar(x % 10 + '0');
}
int main(){
n = Read();
for(int i = 1; i <= n; i++){
bl[i].a = Read(); bl[i].b = Read(); bl[i].w = Read();
bl[i].l = Read(); bl[i].r = Read(); bl[i].p = Read();
Sum += bl[i].b + bl[i].w;
Num[++MAX].val = bl[i].a; Num[MAX].id = MAX;
Num[++MAX].val = bl[i].l; Num[MAX].id = MAX;
Num[++MAX].val = bl[i].r; Num[MAX].id = MAX;
}
sort(Num+1, Num+MAX+1);
Num[0].val = -1; MAX = 0;
for(int i = 1; i <= 3*n; i++){
if(Num[i].val != Num[i-1].val) ++ MAX;
if(Num[i].id % 3 == 1) bl[(Num[i].id-1)/3+1].a = MAX;
if(Num[i].id % 3 == 2) bl[(Num[i].id-1)/3+1].l = MAX;
if(Num[i].id % 3 == 0) bl[(Num[i].id-1)/3+1].r = MAX;
}
s = 1; t = 2;
for(int i = 1; i <= n; i++){
Addedge(s, i+2, bl[i].b);
Addedge(i+2, t, bl[i].w);
Addedge(i+2, i+n+2, bl[i].p);
}
tot = (n << 1) + 2;
Root[0] = NewTnode(); Root[0]->id = ++tot;
for(int i = 1; i <= n; i++){
Root[i] = NewTnode(); *Root[i] = *Root[i-1]; Root[i]->id = ++tot;
Update(Root[i], 1, MAX, bl[i].a, i+2);
Dfs(Root[i-1], 1, MAX, bl[i].l, bl[i].r, i+n+2);
}
Print(Sum - MinCut());
return 0;
}