校內模擬賽 旅行(by NiroBC)

題意:ios

  n個點的無向圖,Q次操做,每次操做能夠鏈接增長一條邊,詢問兩個點之間有多少條邊是必經之路。若是不連通,輸出-1。git

分析:spa

  首先並查集維護連通性,每次加入一條邊後,若是這條邊將會鏈接兩個聯通塊,那麼lct鏈接兩個點,邊權化爲點權,新增一個點,點權爲1。不然,構成了環,環上的邊都變爲0,lct維護覆蓋標記。詢問就是對一條鏈進行詢問。code

  離線+樹剖的作法:從前日後建出樹,若是出現環則不加入,而後樹剖,每次出現一條非樹邊就是將環上的邊賦值爲0,詢問就是兩點之間的邊權和。blog

代碼:get

lctstring

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 200005;
struct LCT{
    #define lc ch[rt][0]
    #define rc ch[rt][1]
    int siz[N], val[N], ch[N][2], fa[N], sk[N], rev[N], tag[N], Index;
    inline bool isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; }
    inline bool son(int x) { return x == ch[fa[x]][1]; }
    inline void pushup(int rt) { siz[rt] = siz[lc] + siz[rc] + val[rt]; }
    inline void pushdown(int rt) {
        if (rev[rt]) {
            swap(lc, rc);
            rev[lc] ^= 1, rev[rc] ^= 1; rev[rt] ^= 1;
        }
        if (tag[rt]) {
            tag[lc] = tag[rc] = 1;
            siz[lc] = siz[rc] = val[lc] = val[rc] = tag[rt] = 0;
        }
    }
    void rotate(int x) {
        int y = fa[x], z = fa[y], c = son(y), b = son(x), a = ch[x][!b];
        if (!isroot(y)) ch[z][c] = x; fa[x] = z;
        ch[x][!b] = y, fa[y] = x;
        ch[y][b] = a; if (a) fa[a] = y;
        pushup(y); pushup(x); 
    }
    void splay(int x) {
        int top = 1; sk[top] = x;
        for (int i = x; !isroot(i); i = fa[i]) sk[++top] = fa[i];
        while (top) pushdown(sk[top --]); // 注意下pushdown到x的下一層 
        while (!isroot(x)) {
            int y = fa[x], z = fa[y];
            if (isroot(y)) rotate(x);
            else {
                if (son(x) == son(y)) rotate(y), rotate(x);
                else rotate(x), rotate(x);
            }
        }
    }
    void access(int x) {
        for (int last = 0; x; last = x, x = fa[x]) 
            splay(x), ch[x][1] = last, pushup(x);
    }
    void makeroot(int x) {
        access(x); splay(x); rev[x] ^= 1;
    }
    void link(int x,int y) {
        makeroot(x); fa[x] = y;
    }
    void add(int x,int y) {
        val[++Index] = 1; link(x, Index); link(Index, y);
    }
    void split(int x,int y) {
        makeroot(x); access(y); splay(y); 
    }
    #undef lc
    #undef rc
}lct;
int fa[N];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
int main() {
    int n = read(), m = read(); lct.Index = n;
    for (int i = 1; i <= n; ++i) fa[i] = i;
    while (m --) {
        int opt = read(), x = read(), y = read(), tx = find(x), ty = find(y);
        if (opt == 1) {
            if (tx != ty) fa[tx] = ty, lct.add(x, y);
            else lct.split(x, y), lct.tag[y] = 1, lct.val[y] = lct.siz[y] = 0;
        } else {
            if (tx != ty) puts("-1");
            else lct.split(x, y), printf("%d\n", lct.siz[y]);
        }
    }
    return 0;
}
相關文章
相關標籤/搜索