校内模拟赛 旅行(by NiroBC)

题意:

  n个点的无向图,Q次操作,每次操作可以连接增加一条边,询问两个点之间有多少条边是必经之路。如果不连通,输出-1。

分析:

  首先并查集维护连通性,每次加入一条边后,如果这条边将会连接两个联通块,那么lct连接两个点,边权化为点权,新增一个点,点权为1。否则,构成了环,环上的边都变为0,lct维护覆盖标记。询问就是对一条链进行询问。

  离线+树剖的做法:从前往后建出树,如果出现环则不加入,然后树剖,每次出现一条非树边就是将环上的边赋值为0,询问就是两点之间的边权和。

代码:

lct

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

 

posted @ 2019-04-02 20:21  MJT12044  阅读(316)  评论(0编辑  收藏  举报