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

题目传送门

http://uoj.ac/problem/77

题解

这题简直丧心病狂,调了一天都没发现自己错在哪。

首先是一个很显然的最小割,见下图。

《UOJ #77. A+B Problem(可持久化线段树+最小割)》

别问我为什么画的这么丑,我…

注意网络中的边都是单向边,边的方向很重要。

与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;
}
    原文作者:B树
    原文地址: https://blog.csdn.net/Ab_Ever/article/details/79751842
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞