cogs 1341 永无乡

【题目描述】

永无乡包含 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。 
 

【样例输入】

  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
  2
  5
  1
  2
  
启发式合并么。。。
用并查集维护岛屿之间的连通性,并打上size标记来维护岛屿集合的大小。
用log数据结构维护每个岛屿集合的所有重要度排名。
合并的时候把小的集合暴力插入到大的集合里。
这样的话每次合并后大小至少乘以二。
最多乘log次,所以最后复杂度是nlog^2n(大概吧。。。)。

平衡树看起来都很难写啊。。。于是并没有写平衡树。。。
01trie还是很好的。。。
注意到n不超过10W。。。
也就是说树的最大深度就是17咯。。。
平衡树的最大深度也是1吧。。。
所以跑进了rank10???
至于01trie怎么合并。。。看置顶的那篇文章吧(神奇的log合并)。。。
STL的list是个坑。。。splice、size操作就是O(n)的。。。
所以手写了一个链表。。。(也就是说key值的合并是O(1)的了。。。当然没什么用。。。毕竟还有O(nlogn)的插入操作。。。)
不过这么说的话vector似乎就行了???
注意垃圾清理啊。。。不然内存要开O(nlog^2n)了(大概)。。。会MLE的(亲测,如果前面的假设没有错的话。。。)。。。


拍照留念?

 
 
  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <list>
  7  
  8 using namespace std;
  9  
 10 const int N = 100010;
 11  
 12 int n, m, q, x, y, id[N];
 13 char op[10];
 14  
 15 int GC[N], gcp;
 16  
 17 int keys[N], hd[N], nxt[N], lst[N];
 18  
 19 int root[N], ch[N * 20][2], sum[N * 20];
 20  
 21 int New() {
 22     static int cnt = 0;
 23     if(gcp) {
 24         int rt =GC[gcp --];
 25         if(rt[ch][0]) {
 26             GC[++ gcp] = rt[ch][0];
 27         }
 28         if(rt[ch][1]) {
 29             GC[++ gcp] = rt[ch][1];
 30         }
 31         rt[ch][0] = rt[ch][1] = 0;
 32         rt[sum] = 0;
 33         return rt;
 34     } else {
 35         return ++ cnt;
 36     }
 37 }
 38  
 39 #define walk for(int i = 16, t ; (t = (val >> i) & 1), ~i ; i --)
 40  
 41 void ins(int rt, int val) {
 42     walk {
 43         if(rt[ch][t] == 0) rt[ch][t] = New();
 44         (rt = rt[ch][t])[sum] ++;
 45     }
 46 }
 47  
 48 int kth(int rt, int val) {
 49     int ret = 0;
 50     walk {
 51         if(val > rt[ch][0][sum]) {
 52             val -= rt[ch][0][sum];
 53             ret |= 1 << i;
 54             rt = rt[ch][1];
 55         } else {
 56             rt = rt[ch][0];
 57         }
 58     }
 59     return ret;
 60 }
 61  
 62 int acc[N], size[N];
 63  
 64 void init(int n) {
 65     for(int i = 1 ; i <= n ; i ++) {
 66         i[acc] = i;
 67         i[size] = 1;
 68     }
 69 }
 70  
 71 int find(int x) {
 72     return x == x[acc] ? x : x[acc] = find(x[acc]);
 73 }
 74  
 75 void uni(int x, int y) {
 76     x = find(x);
 77     y = find(y);
 78     if(x != y) {
 79         y[size] += x[size];
 80         x[acc] = y;
 81     }
 82 }
 83  
 84 void merge(int x, int y) {
 85     x = find(x);
 86     y = find(y);
 87     if(x != y) {
 88         if(x[size] > y[size]) {
 89             swap(x, y);
 90         }
 91         for(int i = x[hd] ; i ; i = nxt[i]) {
 92             ins(y, keys[i]);
 93             if(nxt[i] == 0) {
 94                 y[lst][nxt] = x;
 95                 y[lst] = x[lst];
 96             }
 97         }
 98         GC[++ gcp] = x;
 99         uni(x, y);
100     }
101 }
102  
103 int ask(int rt, int k) {
104     rt = find(rt);
105     if(rt[size] < k) {
106         return -1;
107     } else {
108         int res = kth(rt, k);
109         return res[id];
110     }
111 }
112  
113 int main() {
114     freopen("bzoj_2733.in", "r", stdin);
115     freopen("bzoj_2733.out", "w", stdout);
116     scanf("%d%d", &n, &m);
117     init(n);
118     for(int i = 1 ; i <= n ; i ++) {
119         i[root] = New();
120     }
121     for(int i = 1 ; i <= n ; i ++) {
122         scanf("%d", &x);
123         x[id] = i;
124         ins(i[root], x);
125         i[keys] = x;
126         i[hd] = i;
127         i[lst] = i;
128     }
129     for(int i = 1 ; i <= m ; i ++) {
130         scanf("%d%d", &x, &y);
131         merge(x, y);
132     }
133     scanf("%d", &q);
134     for(int i = 1 ; i <= q ; i ++) {
135         scanf("%s%d%d", op, &x, &y);
136         if(op[0] == 'B') {
137             merge(x, y);
138         } else {
139             printf("%d\n", ask(x, y));
140         }
141     }
142     return 0;
143 }
手写链表版

 

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <vector>
  7 
  8 #define walk for(int i = 16, t ; (t = (val >> i) & 1), ~i ; i --)
  9 
 10 using namespace std;
 11  
 12 const int N = 100010;
 13  
 14 int n, m, q, x, y, id[N];
 15 
 16 char op[10];
 17  
 18 int GC[N], gcp;
 19 
 20 vector<int> keys[N];
 21 
 22 int root[N], ch[N * 20][2], sum[N * 20];
 23 
 24 int acc[N], size[N];
 25 
 26 int New() {
 27     static int cnt = 0;
 28     if(gcp) {
 29         int rt =GC[gcp --];
 30         if(rt[ch][0]) {
 31             GC[++ gcp] = rt[ch][0];
 32         }
 33         if(rt[ch][1]) {
 34             GC[++ gcp] = rt[ch][1];
 35         }
 36         rt[ch][0] = rt[ch][1] = 0;
 37         rt[sum] = 0;
 38         return rt;
 39     } else {
 40         return ++ cnt;
 41     }
 42 }
 43 
 44 void ins(int rt, int val) {
 45     walk {
 46         if(rt[ch][t] == 0) rt[ch][t] = New();
 47         (rt = rt[ch][t])[sum] ++;
 48     }
 49 }
 50  
 51 int kth(int rt, int val) {
 52     int ret = 0;
 53     walk {
 54         if(val > rt[ch][0][sum]) {
 55             val -= rt[ch][0][sum];
 56             ret |= 1 << i;
 57             rt = rt[ch][1];
 58         } else {
 59             rt = rt[ch][0];
 60         }
 61     }
 62     return ret;
 63 }
 64 
 65 void init(int n) {
 66     for(int i = 1 ; i <= n ; i ++) {
 67         i[acc] = i;
 68         i[size] = 1;
 69     }
 70 }
 71  
 72 int find(int x) {
 73     return x == x[acc] ? x : x[acc] = find(x[acc]);
 74 }
 75  
 76 void uni(int x, int y) {
 77     x = find(x);
 78     y = find(y);
 79     if(x != y) {
 80         y[size] += x[size];
 81         x[acc] = y;
 82     }
 83 }
 84  
 85 void merge(int x, int y) {
 86     x = find(x);
 87     y = find(y);
 88     if(x != y) {
 89         if(x[size] > y[size])
 90             swap(x, y);
 91         for(int i = 0 ; i < x[keys].size() ; i ++) {
 92             ins(y, x[keys][i]);
 93             y[keys].push_back(x[keys][i]);
 94         }
 95         GC[++ gcp] = x;
 96         uni(x, y);
 97     }
 98 }
 99  
100 int ask(int rt, int k) {
101     rt = find(rt);
102     if(rt[size] < k) {
103         return -1;
104     } else {
105         int res = kth(rt, k);
106         return res[id];
107     }
108 }
109 
110 int main() {
111     freopen("bzoj_2733.in", "r", stdin);
112     freopen("bzoj_2733.out", "w", stdout);
113  
114     scanf("%d%d", &n, &m);
115     init(n);
116     for(int i = 1 ; i <= n ; i ++) {
117         i[root] = New();
118     }
119  
120     for(int i = 1 ; i <= n ; i ++) {
121         scanf("%d", &x);
122         x[id] = i;
123         ins(i[root], x);
124         i[keys].push_back(x);
125     }
126  
127     for(int i = 1 ; i <= m ; i ++) {
128         scanf("%d%d", &x, &y);
129         merge(x, y);
130     }
131  
132     scanf("%d", &q);
133  
134     for(int i = 1 ; i <= q ; i ++) {
135         scanf("%s%d%d", op, &x, &y);
136         if(op[0] == 'B') {
137             merge(x, y);
138         } else {
139             printf("%d\n", ask(x, y));
140         }
141     }
142     return 0;
143 }
vector版

 



 
 
 
 







 

转载于:https://www.cnblogs.com/KingSann/articles/7351284.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值