題目傳送門
題解
這題簡直喪心病狂,調了一天都沒發現自己錯在哪。
首先是一個很顯然的最小割,見下圖。
別問我爲什麼畫的這麼醜,我…
注意網絡中的邊都是單向邊,邊的方向很重要。
與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
這裏說一下做這題的心路歷程。第一遍寫完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;
}