Luogu3224 HNOI2012 永无乡 线段树合并

传送门

题意:给出$N$个点,每个点有其排名$k_i$($k_i \in [1 , N]$且两两不同),$Q$次操作,操作为在两个点之间连一条边与查询某个点所在连通块内第$K$大排名的点的编号。$N \leq 10^5 , Q \leq 3 \times 10^5$。


查询第$K$大很多时候都用$Splay$,但是在这里显然线段树合并更好用

我们使用并查集维护每个点所在的连通块,线段树叶子节点记录当前排名对应点的编号,非叶子节点记录连通块中对应范围的排名的出现次数。对于第一个操作如果两个点不在同一连通块内就合并,否则什么都不做;对于询问操作在线段树上二分即可。复杂度$O(nlogn)$

  1 #include<bits/stdc++.h>
  2 #define mid ((l + r) >> 1)
  3 //This code is written by Itst
  4 using namespace std;
  5 
  6 inline int read(){
  7     int a = 0;
  8     bool f = 0;
  9     char c = getchar();
 10     while(c != EOF && !isdigit(c)){
 11         if(c == '-')
 12             f = 1;
 13         c = getchar();
 14     }
 15     while(c != EOF && isdigit(c)){
 16         a = (a << 3) + (a << 1) + (c ^ '0');
 17         c = getchar();
 18     }
 19     return f ? -a : a;
 20 }
 21 
 22 const int MAXN = 100010;
 23 struct node{
 24     int l , r , size , ind;
 25 }Tree[MAXN * 30];
 26 int root[MAXN] , fa[MAXN] , N , M , Q , cntNode;
 27 
 28 int find(int x){
 29     return x == fa[x] ? x : (fa[x] = find(fa[x]));
 30 }
 31 
 32 void insert(int& now , int l , int r , int tar , int ind){
 33     if(!now)
 34         now = ++cntNode;
 35     ++Tree[now].size;
 36     if(l == r)
 37         Tree[now].ind = ind;
 38     else
 39         if(mid >= tar)
 40             insert(Tree[now].l , l , mid , tar , ind);
 41         else
 42             insert(Tree[now].r , mid + 1 , r , tar , ind);
 43 }
 44 
 45 int merge(int p , int q){
 46     if(!p)
 47         return q;
 48     if(!q)
 49         return p;
 50     Tree[p].size += Tree[q].size;
 51     Tree[p].l = merge(Tree[p].l , Tree[q].l);
 52     Tree[p].r = merge(Tree[p].r , Tree[q].r);
 53     return p;
 54 }
 55 
 56 int find(int now , int l , int r , int rk){
 57     if(l == r)
 58         return Tree[now].ind;
 59     return Tree[Tree[now].l].size >= rk ? find(Tree[now].l , l , mid , rk) : find(Tree[now].r , mid + 1 , r , rk - Tree[Tree[now].l].size);
 60 }
 61 
 62 inline char getc(){
 63     char c = getchar();
 64     while(!isupper(c))
 65         c = getchar();
 66     return c;
 67 }
 68 
 69 int main(){
 70 #ifndef ONLINE_JUDGE
 71     freopen("3224.in" , "r" , stdin);
 72     //freopen("3224.out" , "w" , stdout);
 73 #endif
 74     N = read();
 75     M = read();
 76     for(int i = 1 ; i <= N ; ++i){
 77         fa[i] = i;
 78         insert(root[i] , 1 , N , read() , i);
 79     }
 80     for(int i = 1 ; i <= M ; ++i){
 81         int a = find(read()) , b = find(read());
 82         if(a != b){
 83             fa[b] = a;
 84             root[a] = merge(root[a] , root[b]);
 85         }
 86     }
 87     for(Q = read() ; Q ; --Q)
 88         if(getc() == 'Q'){
 89             int x = find(read()) , k = read();
 90             printf("%d\n" , Tree[root[x]].size < k ? -1 : find(root[x] , 1 , N , k));
 91         }
 92         else{
 93             int a = find(read()) , b = find(read());
 94             if(a != b){
 95                 fa[b] = a;
 96                 root[a] = merge(root[a] , root[b]);
 97             }
 98         }
 99     return 0;
100 }

猜你喜欢

转载自www.cnblogs.com/Itst/p/10041357.html
今日推荐