zoukankan      html  css  js  c++  java
  • 校内模拟赛 旅行(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
    ", lct.siz[y]);
            }
        }
        return 0;
    }
  • 相关阅读:
    刷题-力扣-700. 二叉搜索树中的搜索
    作业要求20191010-8 alpha week 1/2 Scrum立会报告+燃尽图 06
    20191010-7 alpha week 1/2 Scrum立会报告+燃尽图 05
    20191010-6 alpha week 1/2 Scrum立会报告+燃尽图 04
    20191010-5 alpha week 1/2 Scrum立会报告+燃尽图 03
    20191010-4 alpha week 1/2 Scrum立会报告+燃尽图 02
    20191010-3 alpha week 1/2 Scrum立会报告+燃尽图 01
    扛把子组Scrum立会报告+燃尽图 07
    扛把子组20180926-1 选题展示
    "PSP助手”微信小程序宣传视频链接及内容介绍
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10645044.html
Copyright © 2011-2022 走看看