UOJ #77. A+B Problem(可持久化線段樹+最小割)

題目傳送門

http://uoj.ac/problem/77


題解

這題簡直喪心病狂,調了一天都沒發現自己錯在哪。

首先是一個很顯然的最小割,見下圖。

這裏寫圖片描述

別問我爲什麼畫的這麼醜,我…

注意網絡中的邊都是單向邊,邊的方向很重要。

與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< 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;
}

發佈了177 篇原創文章 · 獲贊 110 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章