zoukankan      html  css  js  c++  java
  • bzoj2733 离线+并查集+主席树

    https://www.lydsy.com/JudgeOnline/problem.php?id=2733

    网上清一色的合并线段树题解,我又不会,只能自己胡来,没想到Rush过去了

    永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。 
     
    
    Input
    输入文件第一行是用空格隔开的两个正整数 n 和 m,分别 表示岛的个数以及一开始存在的桥数。接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai 和 bi,表示一开始就存 在一座连接岛 ai 和岛 bi 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 q, 表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的格式如上所述,以大写字母 Q 或B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。 对于 20%的数据 n≤1000,q≤1000
     
    对于 100%的数据 n≤100000,m≤n,q≤300000 
     
    
    Output
    对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。 
     
    
    Sample Input
    5  1           
    4  3 2 5 1        
    1  2           
    7
    Q 3 2           
    Q 2 1 
    B 2 3 
    B 1 5 
    Q 2 1 
    Q 2 4 
    Q 2 3 
    Sample Output
    -1
    2
    5
    1
    2
    题意

    这是一个只有建桥没有拆桥的操作,很显然可以离线重新排序,将之后会被建桥的区间连在一起,保证之后每次操作都是连续的一个区间。

    然后发现就是维护一个区间K小,上主席树rush!rush!rush!就过了

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,K;
    int val[maxn];
    int nxt[maxn],ed[maxn];
    int fa[maxn];
    void init(){
        For(i,1,N){
            ed[i] = i;
            nxt[i] = -1;
            fa[i] = i;
        }
    }
    int find(int p){
        return p == fa[p]?p:fa[p] = find(fa[p]);
    }
    void Union(int p,int q){
        int fp = find(p),fq = find(q);
        if(fp == fq) return;
        nxt[ed[fp]] = fq;
        ed[fp] = ed[fq];
        fa[fq] = fp;
    }
    struct Node{
        int op,x,y;
        Node(int op = 1,int x = 0,int y = 0):op(op),x(x),y(y) {}
    }node[300010];
    int Index[maxn],tot;
    int T[maxn],lson[maxn * 30],rson[maxn * 30],c[maxn * 30];
    int build(int l,int r){
        int root = tot++;
        c[root] = 0;
        if(l != r){
            int m = (l + r) >> 1;
            lson[root] = build(l,m);
            rson[root] = build(m + 1,r);
        } 
        return root;
    }
    int update(int root,int pos,int val){
        int newroot = tot++,tmp = newroot;
        c[newroot] = c[root] + val;
        int l = 1,r = N;
        while(l < r){
            int m = (l + r) >> 1;
            if(pos <= m){
                lson[newroot] = tot++;
                rson[newroot] = rson[root];
                newroot = lson[newroot];
                root = lson[root];
                r = m;
            }else{
                rson[newroot] = tot++;
                lson[newroot] = lson[root];
                newroot = rson[newroot];
                root = rson[root];
                l = m + 1;
            }
            c[newroot] = c[root] + val;
        }
        return tmp;
    }
    int query(int left_root,int right_root,int k){
        int l = 1,r = N;
        while(l < r){
            int m = (l + r) >> 1;
            if(c[lson[left_root]] - c[lson[right_root]] >= k){
                r = m;
                left_root = lson[left_root];
                right_root = lson[right_root];
            }else{
                l = m + 1;
                k -= c[lson[left_root]] - c[lson[right_root]];
                left_root = rson[left_root];
                right_root = rson[right_root];
            }
        }
        return l;
    }
    int id[maxn];
    PII st[maxn];
    int POS[maxn];
    int main()
    {
        Sca2(N,M);
        For(i,1,N){
            Sca(val[i]);
            id[val[i]] = i;
        }
        init();
        For(i,1,M){
            Sca2(st[i].fi,st[i].se);
            Union(st[i].fi,st[i].se);
        }
        int K; Sca(K);
        For(i,1,K){
            char op[3]; scanf("%s",op);
            Sca2(node[i].x,node[i].y);
            if(op[0] == 'B'){
                node[i].op = 1;
                Union(node[i].x,node[i].y);
            }else{
                node[i].op = 2;
            }
        }
        int cnt = 0;
        For(i,1,N){
            if(i == fa[i]){
                for(int j = i; ~j ; j = nxt[j]){
                    Index[++cnt] = j;
                    POS[j] = cnt;
                }
            }
        }
        T[N + 1] = build(1,N);
        for(int i = N; i ; i --){
            T[i] = update(T[i + 1],val[Index[i]],1);
        }
        init();
        For(i,1,M) Union(st[i].fi,st[i].se);
        for(int i = 1; i <= K ; i ++){
            if(node[i].op == 1){
                Union(node[i].x,node[i].y);
            }else{
                int t = find(node[i].x);
                int l = POS[t];
                int r = POS[ed[t]];
                int k = node[i].y;
                //cout << l << "  " << r << "  " << k << endl;
                if(k > r - l + 1 || k < 1){
                    puts("-1");
                    continue;
                }
                Pri(id[query(T[l],T[r + 1],k)]);
            }
        }
        #ifdef VSCode
        system("pause");
        #endif
        return 0;
    }
  • 相关阅读:
    Linux端口被占用解决
    Django Uwsgi Nginx 部署
    django 取出数据库的时间与当前时间相加减
    C++分支语句
    简单的C++程序
    菜鸟简短的自述以及C++介绍
    springboot maven项目打包SAPJCO3.JAR
    SAPJCO3升级3.1后报错java.lang.UnsatisfiedLinkError: sapjco3.dll解决
    sqlserver 修改数据库用户登录名
    yml字符串值写法,单双引号区别,换行用法
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9850680.html
Copyright © 2011-2022 走看看