[HNOI2012]永无乡

题目描述

永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。

现在有两种操作:

B x y 表示在岛 x 与岛 y 之间修建一座新桥。

Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。

输入输出格式

输入格式:

输入文件第一行是用空格隔开的两个正整数 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

输出格式:

对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。

输入输出样例

输入样例#1:
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
输出样例#1:
-1
2
5
1
2
题解:
splay+并查集
并查集判断两点是否联通,每个节点对应一个平衡树
splay用启发式合并,通过线段树思想和调整顺序可以做到不用旋转

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int MAXN=500010,MAXM=2000005;
  7 int tot2,tot1,s[MAXN],pre[MAXM],ch[MAXM][2],key[MAXM];
  8 int size[MAXM],root[MAXN],n,m,set[MAXN],a[MAXN],sz,id[MAXN];
  9 void NewNode(int &x,int fa,int k)
 10 {
 11     if (tot2) x=s[tot2--];
 12     else x=++tot1;
 13     key[x]=k;
 14     size[x]=1;
 15     pre[x]=fa;
 16     ch[x][0]=ch[x][1]=0;
 17 }
 18 int find(int x)
 19 {
 20     if (set[x]!=x) set[x]=find(set[x]);
 21     return set[x];
 22 }
 23 void pushup(int x)
 24 {
 25     int lson=ch[x][0],rson=ch[x][1];
 26     size[x]=size[lson]+size[rson];
 27 }
 28 void insert(int &x,int l,int r,int d)
 29 {
 30     x=++sz;
 31     if (l==r) 
 32     {
 33      size[x]=1;
 34      return;
 35 }
 36     int mid=(l+r)>>1;
 37      if(d<=mid) insert(ch[x][0],l,mid,d); 
 38      else insert(ch[x][1],mid+1,r,d);
 39      pushup(x);
 40 }
 41 int merge(int x,int y)
 42 {
 43     if (!x) return y;
 44     if (!y) return x;
 45     ch[x][0]=merge(ch[x][0],ch[y][0]);
 46     ch[x][1]=merge(ch[x][1],ch[y][1]);
 47     pushup(x);
 48     return x;
 49 }
 50 int query(int x,int l,int r,int k)
 51 {
 52      if(l==r) return l;
 53      int mid=(l+r)>>1;
 54     if(size[ch[x][0]]>=k) return query(ch[x][0],l,mid,k);
 55     else return query(ch[x][1],mid+1,r,k-size[ch[x][0]]);
 56 }
 57 void erase(int r)
 58 {
 59     if (!r) return ;
 60     s[++tot2]=r;
 61     erase(ch[r][0]);
 62     erase(ch[r][1]);
 63 }
 64 void bridge_union(int x,int y)
 65 {
 66     int l=find(x),r=find(y);
 67     if (l!=r)
 68     {
 69         if (size[root[l]]<size[root[r]]) swap(l,r);
 70          set[r]=l;size[root[l]]+=size[root[r]];
 71          merge(root[l],root[r]);
 72          erase(root[r]);
 73     }
 74 }
 75 char get_op()
 76 {
 77     char ch=getchar();
 78     while (ch!='B'&&ch!='Q') ch=getchar();
 79     return ch;
 80 }
 81 int main()
 82 {int i,j,x,y,q,opt;
 83     cin>>n>>m;
 84       for (i=1;i<=n;i++)
 85       {
 86           scanf("%d",&a[i]);
 87           id[a[i]]=i;
 88            set[i]=i;
 89       }
 90       for (i=1;i<=n;i++)
 91        insert(root[i],1,n,a[i]);
 92        for (i=1;i<=m;i++)
 93        {
 94            scanf("%d%d",&x,&y);
 95            bridge_union(x,y);
 96        }
 97        cin>>q;
 98     for (i=1;i<=q;i++)
 99     {
100         opt=get_op();
101         scanf("%d%d",&x,&y);
102         if (opt=='Q')
103         {
104             int l=find(x);
105              if (size[root[l]]<y) printf("-1
");
106              else 
107             printf("%d
",id[query(root[l],1,n,y)]);
108         }
109         else 
110         {
111             bridge_union(x,y);
112         }
113     }
114 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/7210177.html