题意:
给出一个n个点m条边的森林,每个点有一个点权,有两种操作;
1.查询两点之间的第K小的点权,保证合法;
2.连边(x,y);
m<n<=80000;题解:
论正确姿势的重要性;首先询问和某道COT的题很像,而这道题中多了Link操作;
然而,那道COT的题我是用树链剖分写的。。。一开始的脑洞是每次将小的暴力重构作为一个轻链连在大的树上,然后每隔一段时间重构一次大树;
听起来十分暴力了。。鬼知道能不能过;而正解是COT的正解的姿势,将一个询问分成四个,利用主席树的可减性质,找到LCA然后+x+y-LCA(x,y)-FA(LCA(x,y))像这样处理就可以了;
重构是差不多的,也是启发式合并,维护一下倍增LCA;
注意倍增LCA的数组要清。。小心RE,还是说那么写LCA的只有我一个= =?
空间给的足够的大,所以不需要写垃圾回收了,实际上因为每次重构的是整棵子树,回收是可以的但是有些麻烦。。;
总之还是一道挺好的题(笑);
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 81000
#define M 20002000
#define lson l,mid,ls[no]
#define rson mid+1,r,rs[no]
using namespace std;
typedef long long ll;
int next[N<<1],to[N<<1],head[N],ce;
int val[N],dis[N],len;
int deep[N],fa[N][22],root[N];
int size[M],ls[M],rs[M],tot;
char op[10];
namespace Set
{
int size[N],f[N];
void init(int n)
{
for(int i=1;i<=n;i++)
size[i]=1,f[i]=i;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void Link(int x,int y)
{
x=find(x),y=find(y);
if(x!=y)
{
if(size[x]>size[y])
swap(x,y);
size[y]+=size[x];
f[x]=y;
}
}
}
int newnode()
{
static int ret;
ret=++tot;
ls[ret]=rs[ret]=size[ret]=0;
return ret;
}
void Insert(int l,int r,int &no,int val)
{
int p=newnode();
ls[p]=ls[no],rs[p]=rs[no],size[p]=size[no];
no=p;
size[no]++;
if(l==r) return ;
int mid=l+r>>1;
if(val<=mid) Insert(lson,val);
else Insert(rson,val);
}
int query(int l,int r,int no1,int no2,int no3,int no4,int k)
{
if(l==r)
return l;
else
{
int mid=l+r>>1;
if(k<=size[ls[no1]]+size[ls[no2]]-size[ls[no3]]-size[ls[no4]])
return query(l,mid,ls[no1],ls[no2],ls[no3],ls[no4],k);
else
return query(mid+1,r,rs[no1],rs[no2],rs[no3],rs[no4],
k-size[ls[no1]]-size[ls[no2]]+size[ls[no3]]+size[ls[no4]]);
}
}
void dfs(int x)
{
deep[x]=deep[fa[x][0]]+1;
root[x]=root[fa[x][0]];
Insert(1,len,root[x],val[x]);
memset(fa[x]+1,0,sizeof(int)*21);
for(int i=1;fa[x][i-1];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa[x][0])
{
fa[to[i]][0]=x;
dfs(to[i]);
}
}
}
int LCA(int x,int y)
{
if(x==y) return x;
if(deep[x]<deep[y])
swap(x,y);
int k=20;
while(k>=0)
{
if(deep[fa[x][k]]>=deep[y])
x=fa[x][k];
k--;
}
if(x==y) return x;
k=20;
while(k>=0)
{
if(fa[x][k]!=fa[y][k])
x=fa[x][k],y=fa[y][k];
k--;
}
return fa[x][0];
}
void add(int x,int y)
{
to[++ce]=y;
next[ce]=head[x];
head[x]=ce;
}
int main()
{
int n,m,q,i,j,k,x,y,v,fx,fy,last;
scanf("%*d");
scanf("%d%d%d",&n,&m,&q);
Set::init(n);
for(i=1;i<=n;i++)
scanf("%d",val+i),dis[i]=val[i];
sort(dis+1,dis+n+1);
len=unique(dis+1,dis+n+1)-dis-1;
for(i=1;i<=n;i++)
val[i]=lower_bound(dis+1,dis+len+1,val[i])-dis;
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
Set::Link(x,y);
}
for(i=1;i<=n;i++)
{
if(!deep[i])
dfs(i);
}
for(i=1,last=0;i<=q;i++)
{
scanf("%s%d%d",op,&x,&y);
x^=last,y^=last;
if(op[0]=='Q')
{
scanf("%d",&k);
k^=last;
v=LCA(x,y);
last=dis[query(1,len,root[x],root[y],root[v],root[fa[v][0]],k)];
printf("%d\n",last);
}
else
{
fx=Set::find(x),fy=Set::find(y);
if(Set::size[fx]>Set::size[fy])
swap(x,y),swap(fx,fy);
Set::Link(x,y);
fa[x][0]=y;
dfs(x);
add(x,y),add(y,x);
}
}
return 0;
}