日常訓練 20170606 極地旅行社

題目描述

不久之前,Mirko建立了一個旅行社,名叫“極地之夢”。這家旅行社在北極附近購買了 N 座冰島,並且提供觀光服務。當地最受歡迎的當然是帝企鵝了,這些小傢伙經常成羣結隊的遊走在各個冰島之間。

Mirko的旅行社遭受一次重大打擊,以至於觀光遊輪已經不划算了。旅行社將在冰島之間建造大橋,並用觀光巴士來運載遊客。Mirko希望開發一個電腦程序來管理這些大橋的建造過程,以免有不可預料的錯誤發生。

這些冰島從 1N 標號。一開始時這些島嶼沒有大橋連接,並且所有島上的帝企鵝數量都是知道的。每座島上的企鵝數量雖然會有所改變,但是始終在 [0,1000] 之間。

你的程序需要處理以下三種命令:

bridge A B :在 A 與 B 之間建立一座大橋(A 與 B 是不同的島嶼)。由於經費限制,這項命令被接受,當且僅當 A 與 B 不聯通。若這項命令被接受,你的程序需要輸出yes,之後會建造這座大橋。否則,你的程序需要輸出no。

penguins A X :根據可靠消息,島嶼 A此時的帝企鵝數量變爲 X。這項命令只是用來提供信息的,你的程序不需要回應。

excursion A B :一個旅行團希望從 A 出發到 B。若 A 與 B 連通,你的程序需要輸出這個旅行團一路上所能看到的帝企鵝數量(包括起點 A 與終點 B ),若不聯通,你的程序需要輸出impossible。

輸入格式

第一行一個正整數 N ,表示冰島的數量。

第二行 N 個範圍 [0,1000] 的整數,爲每座島嶼初始的帝企鵝數量。

第三行一個正整數 M ,表示命令的數量。

接下來 M 行即命令,爲題目描述所示。

輸出格式

對於每個bridge命令與excursion命令,輸出一行,爲題目描述所示。

一開始以爲是LCT,然而我太弱以至於根本不會LCT,DJY提醒我只要樹剖就可以了,強行被報標算,不A都對不起良心了。對於bridge只要用並查集判斷即可,對於excursion在第一遍並查集的時候順便記一下要不要輸 impossible ,然後把森林連到虛點上變成一棵樹,建出樹後樹剖一下,只要維護一下區間和即可。

#include<bits/stdc++.h>
const int N = 3e4 + 10;
const int M = 1e5 + 10;
template <typename T> void read(T &x) {
    x = 0; char c = getchar();
    for (; !isdigit(c); c = getchar());
    for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
}
int n, m, a[N], f[N], first[N], s;
char op[10];
struct edge{
    int y, next;
}mp[N * 4];
void ins(int x, int y) {
    mp[++s] = (edge) {y, first[x]}; first[x] = s;
    mp[++s] = (edge) {x, first[y]}; first[y] = s;
}
int find(int x) {
    if (f[x] == x) return x;
    return f[x] = find(f[x]);
}
namespace force {
    int x, y;
    void bridge(int x, int y) {
        int f1 = find(x);
        int f2 = find(y);
        if (f1 == f2) {printf("no\n"); return;}
        printf("yes\n");
        f[f1] = f2;
        ins(x, y);
    }
    bool dfs(int x, int y, int sum, int last) {
        if (x == y) {printf("%d\n", sum); return 1;}
        for (int t=first[x]; t; t=mp[t].next)
            if (mp[t].y != last && dfs(mp[t].y, y, sum + a[mp[t].y], x))
                return 1;
        return 0;
    }
    int main() {
        read(n);
        for (int i=1; i <= n; i++)
            read(a[i]), f[i] = i;
        read(m);
        while (m--) {
            scanf("%s", op);
            read(x); read(y);
            if (op[0] == 'b') bridge(x, y);
            if (op[0] == 'p') a[x] = y;
            if (op[0] == 'e') if (!dfs(x, y, a[x], -1)) printf("impossible\n");
        }
        return 0;
    }
}
namespace try_it {
    int x[M], y[M];
    char opt[M];
    int fa[N][20], size[N], top[N], dep[N], pos[N], cnt;
    int lc[N * 4], rc[N * 4], sum[N * 4], node;
    bool z[M], vis[N];
    bool bridge(int x, int y) {
        int f1 = find(x);
        int f2 = find(y);
        if (f1 == f2) return 0;
        f[f1] = f2; ins(x, y);
        return 1;
    }
    void dfs1(int x) {
        vis[x] = 1;
        for (int t=first[x]; t; t=mp[t].next)
            if (!vis[mp[t].y]) dfs1(mp[t].y);
    }
    int dfs2(int x) {
        for (int i=1; dep[x] - (1 << i) >= 0; i++)
            fa[x][i] = fa[fa[x][i - 1]][i - 1];
        size[x] = 1;
        for (int t=first[x]; t; t=mp[t].next)
            if (mp[t].y != fa[x][0])
                fa[mp[t].y][0] = x,
                dep[mp[t].y] = dep[x] + 1,
                size[x] += dfs2(mp[t].y);
        return size[x];
    }
    void dfs3(int x, int cap) {
        top[x] = cap;
        pos[x] = ++cnt;
        int mxszi = 0;
        for (int t=first[x]; t; t=mp[t].next)
            if (mp[t].y != fa[x][0] && size[mp[t].y] > size[mxszi])
                mxszi = mp[t].y;
        if (!mxszi) return;
        dfs3(mxszi, cap);
        for (int t=first[x]; t; t=mp[t].next)
            if (mp[t].y != fa[x][0] && mp[t].y != mxszi)
                dfs3(mp[t].y, mp[t].y);
    }
    void build(int i, int l, int r) {
        if (l == r) return;
        lc[i] = ++node; build(lc[i], l, (l + r) / 2);
        rc[i] = ++node; build(rc[i], (l + r) / 2 + 1, r);
    }
    void chg(int i, int l, int r, int x, int c) {
        if (l == r) {sum[i] = c; return;}
        if (x <= (l + r) / 2)
            chg(lc[i], l, (l + r) / 2, x, c);
        else
            chg(rc[i], (l + r) / 2 + 1, r, x, c);
        sum[i] = sum[lc[i]] + sum[rc[i]];
    }
    int lca(int x, int y) {
        if (dep[x] < dep[y]) std::swap(x, y);
        for (int i=19; i >= 0; i--)
            if (dep[x] - (1 << i) >= dep[y])
                x = fa[x][i];
        for (int i=19; i >= 0; i--)
            if (fa[x][i] != fa[y][i])
                x = fa[x][i],
                y = fa[y][i];
        if (x == y) return x;
        return fa[x][0];
    }
    int qry(int i, int l, int r, int _l, int _r) {
        if (l > _r || r < _l) return 0;
        if (l >= _l && r <= _r) return sum[i];
        return qry(lc[i], l, (l + r) / 2, _l, _r) + qry(rc[i], (l + r) / 2 + 1, r, _l, _r);
    }
    int qry(int x, int y) {
        int l = lca(x, y), ret = - a[l];
        while (dep[top[x]] > dep[l]) ret += qry(1, 1, cnt, pos[top[x]], pos[x]), x = fa[top[x]][0];
        ret += qry(1, 1, cnt, pos[l], pos[x]);
        while (dep[top[y]] > dep[l]) ret += qry(1, 1, cnt, pos[top[y]], pos[y]), y = fa[top[y]][0];
        ret += qry(1, 1, cnt, pos[l], pos[y]);
        return ret;
    }
    int main() {
        read(n);
        for (int i=1; i <= n; i++)
            read(a[i]), f[i] = i;
        read(m);
        for (int i=1; i <= m; i++) {
            scanf("%s", op);
            opt[i] = op[0];
            read(x[i]); read(y[i]);
            if (opt[i] == 'b') z[i] = bridge(x[i], y[i]);
            if (opt[i] == 'e') z[i] = find(x[i]) == find(y[i]);
        }
        for (int i=1; i <= n; i++)
            if (!vis[i]) dfs1(i), ins(n + 1, i);
        dfs2(n + 1);
        dfs3(n + 1, n + 1);
        node = 1; build(1, 1, cnt);
        for (int i=1; i <= n; i++) chg(1, 1, cnt, pos[i], a[i]);
        for (int i=1; i <= m; i++) {
            if (opt[i] == 'b') if (z[i]) printf("yes\n"); else printf("no\n"); else;
            if (opt[i] == 'p') chg(1, 1, cnt, pos[x[i]], y[i]), a[x[i]] = y[i];
            if (opt[i] == 'e') if (z[i]) printf("%d\n", qry(x[i], y[i])); 
                                    else printf("impossible\n"); else;
        }
        return 0;
    }
}
int main() {
    //force::main();
    try_it::main();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章