1.知识点
splay+并查集+启发式合并
2.思路
维护n颗splay,再通过并查集+启发式合并(暴力 )维护。
const int N = 1800010;//n+logn
struct node
{
int s[2], p, v, id, size; //儿子,父亲,重要度(排序关键字),初始编号,维护大小用于get_k
void init(int _v, int _id, int _p)
{
v = _v;
id = _id;
p = _p;
size = 1;
}
} tr[N];
int n, m, idx;
int p[N], root[N]; //并查集数组,N颗splay
3.代码+注释
#include <bits/stdc++.h>
using namespace std;
//-----pre_def----
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define fir(i, a, b) for (int i = (a); i <= (b); i++)
#define rif(i, a, b) for (int i = (a); i >= (b); i--)
#define endl '\n'
#define init_h memset(h, -1, sizeof h), idx = 0;
#define lowbit(x) x &(-x)
//---------------
const int N = 1800010;
struct node
{
int s[2], p, v, id, size; //儿子,父亲,重要度(排序关键字),初始编号,维护大小用于get_k
void init(int _v, int _id, int _p)
{
v = _v;
id = _id;
p = _p;
size = 1;
}
} tr[N];
int n, m, idx;
int p[N], root[N]; //并查集数组,N颗splay
int find(int x)
{
if (x != p[x])
p[x] = find(p[x]);
return p[x];
}
//splay
void pushup(int u)
{
tr[u].size = tr[tr[u].s[0]].size + tr[tr[u].s[1]].size + 1;
}
void rotate(int u)
{
int y = tr[u].p, z = tr[y].p;
int k = tr[y].s[1] == u;
tr[z].s[tr[z].s[1] == y] = u, tr[u].p = z;
tr[y].s[k] = tr[u].s[k ^ 1], tr[tr[u].s[k ^ 1]].p = y;
tr[u].s[k ^ 1] = y, tr[y].p = u;
pushup(y), pushup(u);
}
void splay(int x, int k, int b)//
{
while (tr[x].p != k)
{
int y = tr[x].p, z = tr[y].p;
if (z != k)
if ((tr[y].s[1] == x) ^ (tr[z].s[1] == y))
rotate(x);
else
rotate(y);
rotate(x);
}
if (!k)
root[b] = x;
}
void insert(int v, int id, int b)
{
int u = root[b], p = 0;
while (u)
p = u, u = tr[u].s[v > tr[u].v];
u = idx++;
if (p)
tr[p].s[v > tr[p].v] = u;
tr[u].init(v, id, p);
splay(u, 0, b);
}
int get_k(int k, int b)//可以理解为第b颗splay
{
int u = root[b];
while (u)
{
if (tr[tr[u].s[0]].size >= k)
u = tr[u].s[0];
else if (tr[tr[u].s[0]].size + 1 == k)
return tr[u].id;
else
k -= tr[tr[u].s[0]].size + 1, u = tr[u].s[1];
}
return -1;
}
void dfs(int a, int b)
{
if (tr[a].s[0])
dfs(tr[a].s[0], b);
if (tr[a].s[1])
dfs(tr[a].s[1], b);
insert(tr[a].v, tr[a].id, b);
}
void init()
{
fir(i, 1, n)
{
int x;
scanf("%d", &x);
p[i] = i;
root[i] = i;
tr[i].init(x, i, 0);
}
idx = n + 1;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
int StartTime = clock();
#endif
scanf("%d%d", &n, &m);
init();
while (m--)
{
int a, b;
scanf("%d%d", &a, &b);
a = find(a), b = find(b);
if (a != b)
{
if (tr[root[a]].size > tr[root[b]].size)
swap(a, b);
dfs(root[a], b); //启发式合并操作
p[a] = b;//此时root[a]废弃了
}
}
scanf("%d", &m);
while (m--)
{
char op[2];
int a, b;
scanf("%s%d%d", op, &a, &b);
if (*op == 'Q')
{
a = find(a);
if (tr[root[a]].size < b)
puts("-1");
else
printf("%d\n", get_k(b, a));
}
else
{
a = find(a), b = find(b);
if (a != b)
{
if (tr[root[a]].size > tr[root[b]].size)
swap(a, b);
dfs(root[a], b); //启发式合并操作
p[a] = b;//此时root[a]废弃了
}
}
}
#ifndef ONLINE_JUDGE
printf("Run_Time = %d ms\n", clock() - StartTime);
#endif
return 0;
}
4.总结
思路简单,但是很难写。
还要多刷题熟练模板。