BZOJ2843: 极地旅行社 LCT 或 LCA+dfs序+树状数组+并查集

版权声明:xgc原创文章,未经允许不得转载。 https://blog.csdn.net/xgc_woker/article/details/80109312

Description
你的程序需要处理以下三种命令:
1.”bridge A B”——在A与B之间建立一座大桥(A与B是不同的岛屿)。由于经费限制,这项命令被接受,当且仅当
A与B不联通。若这项命令被接受,你的程序需要输出”yes”,之
后会建造这座大桥。否则,你的程序需要输出”no”。
2.”penguins A X”——根据可靠消息,岛屿A此时的帝企鹅数量变为X。这项命令只是用来提供信息的,你的程序不
需要回应。
3.”excursion A B”——一个旅行团希望从A出发到B。若A与B连通,你的程序需要输出这个旅行团一路上所能看到的
帝企鹅数量(包括起点A与终点B),若不联通,你的程序需要输出”impossible”。


Sample Input
5
4 2 4 5 6
10
excursion 1 1
excursion 1 2
bridge 1 2
excursion 1 2
bridge 3 4
bridge 3 5
excursion 4 5
bridge 1 3
excursion 2 4
excursion 2 5


Sample Output
4
impossible
yes
6
yes
yes
15
yes
15
16


这道题LCT版题。
好像还可以离线做,改日来水。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
int _max(int x, int y) {return x > y ? x : y;}

struct node {
    int f, s, d, lazy, son[2];
} t[310000];
int tp, temp[310000];
char ss[11];

void Lazy(int x) {
    if(!t[x].lazy) return ;
    t[x].lazy = 0;
    swap(t[x].son[0], t[x].son[1]);
    int lc = t[x].son[0], rc = t[x].son[1];
    if(lc) t[lc].lazy ^= 1;
    if(rc) t[rc].lazy ^= 1;
}

void update(int x) {
    int lc = t[x].son[0], rc = t[x].son[1];
    t[x].s = t[x].d + t[lc].s + t[rc].s;
}

void rotate(int x, int fx) {
    int f = t[x].f, ff = t[f].f;
    int r, R;

    r = t[x].son[fx], R = f;
    if(r) t[r].f = R;
    t[R].son[1 ^ fx] = r;

    r = x, R = ff;
    t[r].f = R;
    if(t[ff].son[0] == f) t[R].son[0] = r; else if(t[ff].son[1] == f) t[R].son[1] = r;

    r = f, R = x;
    t[r].f = R;
    t[R].son[fx] = r;

    update(f);
    update(x);
}

bool hh(int x) {
    int f = t[x].f;
    if(f == 0 || (t[f].son[0] != x && t[f].son[1] != x)) return 0;
    return 1;
}

void splay(int x) {
    int i = x; tp = 0;
    while(hh(i)) temp[++tp] = i, i = t[i].f;
    temp[++tp] = i;
    for(int i = tp; i >= 1; i--) Lazy(temp[i]);
    while(hh(x)) {
        int f = t[x].f, ff = t[f].f;
        if(!hh(f)) {
            if(t[f].son[0] == x) rotate(x, 1);
            else rotate(x, 0);
        }
        else if(t[ff].son[0] == f && t[f].son[0] == x) rotate(f, 1), rotate(x, 1);
        else if(t[ff].son[0] == f && t[f].son[1] == x) rotate(x, 0), rotate(x, 1);
        else if(t[ff].son[1] == f && t[f].son[1] == x) rotate(f, 0), rotate(x, 0);
        else if(t[ff].son[1] == f && t[f].son[0] == x) rotate(x, 1), rotate(x, 0);
    }
}

void Access(int x) {
    int y = 0;
    while(x) {
        splay(x);
        t[x].son[1] = y;
        if(y) t[y].f = x;
        update(x);
        y = x; x = t[x].f;
    }
}

void Makert(int x) {
    Access(x); splay(x);
    t[x].lazy ^= 1;
}

void Link(int x, int y) {
    Makert(x); t[x].f = y; Access(x);
}

int Findrt(int x) {
    Access(x); splay(x);
    while(t[x].son[0]) x = t[x].son[0];
    return x;
}

int finds(int x, int y) {
    Makert(x);
    Access(y); splay(y);
    return t[y].s;
}

int main() {
    int n; scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        int x; scanf("%d", &x);
        t[i].d = t[i].s = x;
    }
    int m; scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        scanf("%s", ss + 1);
        int x, y; scanf("%d%d", &x, &y);
        if(ss[1] == 'b') {
            if(Findrt(x) == Findrt(y)) {
                printf("no\n");
                continue;
            }
            else printf("yes\n");
            Link(x, y);
        }
        else if(ss[1] == 'p') {
            Makert(x);
            t[x].d = y;
            update(x);
        }
        else {
            if(Findrt(x) != Findrt(y)) {
                printf("impossible\n");
                continue;
            }
            printf("%d\n", finds(x, y));
        }
    }
    return 0;
}

我来补离线水法啦。
因为你如果联通,肯定s值是固定的。
于是你先建出树,离线搞一下。
树状数组维护一下,并查集判一下联通。


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct edge {
    int x, y, next;
} e[61000]; int len, last[31000];
struct node {
    int opt, x, y;
} b[110000];
int f[31000], a[31000], s[31000], dep[31000], fa[31000][18];
int n, id, ll[31000], rr[31000];
bool v[31000];
char ss[11];

int lowbit(int x) {return x & -x;}
void change(int x, int c) {
    for(int i = x; i <= n; i += lowbit(i)) s[i] += c;
}
int getsum(int x) {
    int sum = 0;
    for(int i = x; i >= 1; i -= lowbit(i)) sum += s[i];
    return sum;
}

void ins(int x, int y) {
    e[++len].x = x; e[len].y = y;
    e[len].next = last[x]; last[x] = len;
}

int findfa(int x) {
    if(f[x] != x) f[x] = findfa(f[x]);
    return f[x];
}

void dfs(int x) {
    ll[x] = ++id;
    v[x] = 1;
    for(int i = 1; i <= 16; i++) fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for(int k = last[x]; k; k = e[k].next) {
        int y = e[k].y;
        if(y != fa[x][0]) {
            fa[y][0] = x;
            dep[y] = dep[x] + 1;
            dfs(y);
        }
    } rr[x] = id;
}

int LCA(int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    for(int i = 16; i >= 0; i--)
        if(dep[x] - dep[y] >= (1 << i))
            x = fa[x][i];
    if(x == y) return x;
    for(int i = 16; i >= 0; i--)
        if(fa[x][i] != fa[y][i])
            x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]), f[i] = i;
    int m; scanf("%d", &m);
    for(int i = 1; i <= m; i++) {
        scanf("%s", ss + 1);
        scanf("%d%d", &b[i].x, &b[i].y);
        if(ss[1] == 'b') {
            int fx = findfa(b[i].x), fy = findfa(b[i].y);
            if(fx != fy) {
                f[fx] = fy;
                ins(b[i].x, b[i].y); ins(b[i].y, b[i].x);
            }
            b[i].opt = 1;
        }
        else if(ss[1] == 'p') b[i].opt = 2;
        else b[i].opt = 3;
    }
    for(int i = 1; i <= n; i++)
        if(!v[i]) dfs(i);
    for(int i = 1; i <= n; i++) f[i] = i, change(ll[i], a[i]), change(rr[i] + 1, -a[i]);
    for(int i = 1; i <= m; i++) {
        if(b[i].opt == 1) {
            int fx = findfa(b[i].x), fy = findfa(b[i].y);
            if(fx != fy) {
                f[fx] = fy;
                printf("yes\n");
            }
            else printf("no\n");
        }
        else if(b[i].opt == 2) {
            change(ll[b[i].x], b[i].y - a[b[i].x]);
            change(rr[b[i].x] + 1, a[b[i].x] - b[i].y);
            a[b[i].x] = b[i].y;
        }
        else {
            int fx = findfa(b[i].x), fy = findfa(b[i].y);
            if(fx == fy) {
                int lca = LCA(b[i].x, b[i].y);
                int ss = getsum(ll[b[i].x]) + getsum(ll[b[i].y]);
                ss -= getsum(ll[lca]) + getsum(ll[fa[lca][0]]);
                printf("%d\n", ss);
            }
            else printf("impossible\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/80109312