题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2733
题目大意:有n座小岛和m座桥,每座岛都有一个独一无二的重要度,给你两种操作:1.在x,y两座岛间架一座桥,2.询问与x连通的岛中第k重要的岛是哪座
乍一看真的是很难下手的一道题……直到前天晚上我学到了splay的启发式合并……
回忆:
学长:splay有合并操作的
我:怎么可能能合并啊……
学长:如果让你合并你怎么做?
我:[斜眼]暴力重建
学长:说的好
我:……
学长:不过可以把暴力重建改一下
我:怎么改?
学长:启发式合并,把小的暴力扔到大的上
我:……能快多少?
学长:均摊后是O(logn)的
我:………………………………
于是这道题就好办了……开始每个节点都建一棵splay,建立桥的操作就是合并操作,查询第k大这是基本功能了吧……
开始的时候我试着同时维护并查集和splay,于是跪的很惨………………
贴代码
#include <iostream>
#include <cstdio>
using namespace std;
struct island
{
int s[2],f;
int val,sz;
}a[200000];
int tem[200000];
bool son(int x)
{
return a[a[x].f].s[1] == x;
}
void rejs(int x)
{
a[x].sz = a[a[x].s[0]].sz + a[a[x].s[1]].sz + 1;
}
void point(int x,int y,bool z)
{
a[x].s[z] = y;
a[y].f = x;
}
void rot(int x)
{
int d = son(x);
int p = a[x].f;
point(a[p].f,x,son(p));
point(p,a[x].s[d^1],d);
point(x,p,d^1);
rejs(p);
rejs(x);
}
void splay(int x)
{
while(a[x].f)
{
if(!a[a[x].f].f)
rot(x);
else if(son(x) == son(a[x].f))
{
rot(a[x].f);
rot(x);
}
else
{
rot(x);
rot(x);
}
}
}
void ins(int w,int x)
{
int k;
while(w)
{
k = w;
if(a[x].val < a[w].val)
w = a[w].s[0];
else
w = a[w].s[1];
}
if(a[k].val > a[x].val)
point(k,x,0);
else
point(k,x,1);
splay(x);
}
void clr(int x)
{
a[x].f = 0;
a[x].s[0] = 0;
a[x].s[1] = 0;
a[x].sz = 1;
}
int root(int x)
{
while(a[x].f)
x = a[x].f;
return x;
}
int findk(int t,int x)
{
t = root(t);
if(a[t].sz < x)
return -1;
int k = a[a[t].s[0]].sz + 1;
while(233)
{
if(x == k)
return t;
if(x < k)
{
t = a[t].s[0];
k -= a[a[t].s[1]].sz + 1;
}
else
{
t = a[t].s[1];
k += a[a[t].s[0]].sz + 1;
}
}
}
void lyne(int x,int y)
{
x = root(x);
y = root(y);
if(x == y)
return ;
if(a[y].sz > a[x].sz)
swap(x,y);
for(int i = 1;i <= a[y].sz;i ++)
tem[i] = findk(y,i);
int n = a[y].sz;
for(int i = 1;i <= n;i ++)
{
clr(tem[i]);
ins(x,tem[i]);
}
}
int main()
{
int n,m,x,y;
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++)
{
scanf("%d",&a[i].val);
a[i].sz = 1;
}
for(int i = 1;i <= m;i ++)
{
scanf("%d%d",&x,&y);
lyne(x,y);
}
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
{
char w[10];
scanf("%s",w);
scanf("%d%d",&x,&y);
if(w[0] == 'B')
lyne(x,y);
else
printf("%d\n",findk(x,y));
}
return 0;
}