Description
小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值。初始的时候,森林中有M条边。
小Z希望执行T个操作,操作有两类:
Q x y k查询点x到点y路径上所有的权值中,第k小的权值是多少。此操作保证点x和点y连通,同时这两个节点的路径上至少有k个点。
L x y在点x和点y之间连接一条边。保证完成此操作后,仍然是一片森林。
为了体现程序的在线性,我们把输入数据进行了加密。设lastans为程序上一次输出的结果,初始的时候lastans为0。
对于一个输入的操作Q x y k,其真实操作为Q x^lastans y^lastans k^lastans。
对于一个输入的操作L x y,其真实操作为L x^lastans y^lastans。其中^运算符表示异或,等价于pascal中的xor运算符。
请写一个程序來帮助小Z完成这些操作。
对于所有的数据,n,m,T<= 8∗10^4
Solution
最开始想到的是开两棵LCT分别搞形态和权值,然后我显然不会写
接着考虑树上开主席树,启发式合并,然后就过了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))
const int LIM=1000000000;
const int N=200005;
const int E=400005;
struct edge {int x,y,next;} e[E];
struct treeNode {int l,r,sum;} t[N*81];
int dep[N],fa[N][19],size[N];
int root[N],a[N],tot;
int ls[N],acs[N],edCnt;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add_edge(int x,int y) {
e[++edCnt]=(edge) {x,y,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge) {y,x,ls[y]}; ls[y]=edCnt;
}
void modify(int pre,int &now,int tl,int tr,int x,int v) {
t[now=++tot]=t[pre]; t[now].sum++;
if (tl==tr) return ;
int mid=(tl+tr)>>1;
if (x<=mid) modify(t[pre].l,t[now].l,tl,mid,x,v);
else modify(t[pre].r,t[now].r,mid+1,tr,x,v);
}
int query(int lca,int flca,int x,int y,int tl,int tr,int k) {
if (tl==tr) return tl;
int tmp=t[t[x].l].sum+t[t[y].l].sum-t[t[lca].l].sum-t[t[flca].l].sum;
int mid=(tl+tr)>>1;
if (tmp>=k) return query(t[lca].l,t[flca].l,t[x].l,t[y].l,tl,mid,k);
else return query(t[lca].r,t[flca].r,t[x].r,t[y].r,mid+1,tr,k-tmp);
}
void dfs(int now) {
size[now]=1; acs[now]=fa[now][0];
rep(i,1,18) fa[now][i]=fa[fa[now][i-1]][i-1];
modify(root[fa[now][0]],root[now],1,LIM,a[now],1);
for (int i=ls[now];i;i=e[i].next) {
if (e[i].y==fa[now][0]) continue;
fa[e[i].y][0]=now;
dep[e[i].y]=dep[now]+1;
dfs(e[i].y);
size[now]+=size[e[i].y];
}
}
int get_lca(int x,int y) {
if (dep[x]<dep[y]) std:: swap(x,y);
drp(i,18,0) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if (x==y) return x;
drp(i,18,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int get_father(int x) {
if (!acs[x]) return x;
return acs[x]=get_father(acs[x]);
}
int main(void) {
int WJP=read();
int n=read(),m=read(),T=read();
rep(i,1,n) a[i]=read();
rep(i,1,m) add_edge(read(),read());
rep(i,1,n) if (!dep[i]) {
dep[i]=1;
dfs(i);
}
for (int lastans=0;T--;) {
char opt[2]; scanf("%s",opt);
int x=read()^lastans,y=read()^lastans;
if (opt[0]=='Q') {
int k=read()^lastans;
int lca=get_lca(x,y);
int flca=fa[lca][0];
lastans=query(root[lca],root[flca],root[x],root[y],1,LIM,k);
printf("%d\n", lastans);
} else {
if (size[get_father(x)]<size[get_father(y)]) std:: swap(x,y);
fa[y][0]=x; dep[y]=dep[x]+1; add_edge(x,y);
size[get_father(x)]+=size[get_father(y)];
dfs(y);
}
}
return 0;
}