传送门

强制在线资瓷连边的树上$K$大(小)值。

静态树上$K$大值可以用主席树,结合$LCA$加加减减就行。

要求连边,可以启发式合并主席树。其实也可以说重构主席树。维护一下每个点所在的树的$size$,连接两点,选择$size$较小的连到较大的上去,即重新$dfs$一遍。

由于每个点合并一次后$size$至少翻倍,所以最多被合并$logn$次。重构一个点主席树复杂度为$O(logn)$,总复杂度$O(nlog^2n)$。

维护$size$珂以用并查集。因为要改变树的形态,树剖$LCA$不能用了,珂以用倍增$LCA$或者$LCT$求$LCA$。(蒟蒻以前一直用的树剖$LCA$,结果倍增写假了调了两天$QAQ$)

空间上可以重复利用之前的点,不过蒟蒻懒得写想省时间所以没有,所以单点重构主席树要开$O(logn)$个节点,空间复杂度$O(nlog^2n)$。

细节:值域很大,需要离散化

代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>

#define maxn 80005
#define inf 0x3f3f3f3f
#define pn putchar('\n')
#define px(x) putchar(x)
#define ps putchar(' ')
#define pd puts("======================")
#define pj puts("++++++++++++++++++++++")

using namespace std;

inline int read(){
    int x=0,y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
template<typename T>
inline T read(){
    T x=0;
    int y=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return y?-x:x;
}
int h[maxn],num,F[maxn],siz[maxn];
//F是并查集
struct edge{
    int pre,to;
}e[maxn<<1];
inline void add(int from,int to){
    e[++num].pre=h[from],h[from]=num,e[num].to=to;
}
int find(int x){
    if(F[x]==x)return x;
    return F[x]=find(F[x]);
}
int n,len,dis[maxn],a[maxn],root[maxn],fa[maxn][32],lg[maxn],deep[maxn];
//dis是离散化数组
struct Chairman_Tree{
    int dat[maxn*400],ls[maxn*400],rs[maxn*400],cnt;
#define ls(x) ls[x]
#define rs(x) rs[x]
    void build(int poi,int ne,int ol){
        int l=1,r=len;
        while(l<r){
            dat[ne]=dat[ol]+1;
            int mid=l+r>>1;
            if(poi<=mid)rs(ne)=rs(ol),ol=ls(ol),ne=ls(ne)=++cnt,r=mid;    
            else ls(ne)=ls(ol),ol=rs(ol),ne=rs(ne)=++cnt,l=mid+1;
        }
        dat[ne]=dat[ol]+1;
    }//主席树重构
    int ask(int x,int y,int lc,int fl,int k){
        //lc是lca,fl为lca的父亲
        int l=1,r=len;
        while(l<r){
            int mid=l+r>>1,sum=dat[ls(x)]+dat[ls(y)]-dat[ls(lc)]-dat[ls(fl)];
            if(sum>=k)x=ls(x),y=ls(y),lc=ls(lc),fl=ls(fl),r=mid;
            else x=rs(x),y=rs(y),lc=rs(lc),fl=rs(fl),l=mid+1,k-=sum;
        }
        return dis[l];
    }//查询
}ct;
int lca(int x,int y){
    if(deep[x]<deep[y])swap(x,y);
    while(deep[x]>deep[y])x=fa[x][lg[deep[x]-deep[y]]-1];
    if(x==y)return x;
    for(register int i=lg[deep[x]];i>=0;--i)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}//倍增lca
void dfs(int node,int f){
    deep[node]=deep[f]+1;
    root[node]=++ct.cnt;
    ct.build(a[node],root[node],root[f]);
    fa[node][0]=f;
    int top=lg[deep[node]];
    for(register int i=1;i<=top;++i)
        fa[node][i]=fa[fa[node][i-1]][i-1];
    for(register int i=h[node];i;i=e[i].pre){
        int x=e[i].to;
        if(x!=f)siz[node]+=siz[x],dfs(x,node);
    }    
}
void merge(int x,int y){
    add(x,y),add(y,x);
    int u=find(x),v=find(y);
    if(siz[u]>siz[v])swap(x,y),swap(u,v);
    siz[v]+=siz[u];
    dfs(x,y);
}
int spget(){
    char ch=getchar();
    while(ch!='Q'&&ch!='L')ch=getchar();
    return ch=='Q';
}//获取字符的
int main(){
    read();
    n=read();
    int m=read(),t=read();
    for(register int i=1;i<=n;++i)
        F[i]=i,a[i]=dis[i]=read(),lg[i]=lg[i-1]+(1<<lg[i-1]==i);
    sort(dis+1,dis+1+n);
    len=unique(dis+1,dis+1+n)-dis-1;
    for(register int i=1;i<=n;++i)
        a[i]=lower_bound(dis+1,dis+1+len,a[i])-dis;
    //离散化
    for(register int i=1;i<=m;++i){
        int a=read(),b=read();
        add(a,b),add(b,a);
    }
    for(register int i=1;i<=n;++i)
        if(!deep[i])dfs(i,0);
    for(register int i=1;i<=n;++i)
        if(fa[i][0])F[i]=fa[i][0];
    //初始化并查集
    for(register int i=1;i<=n;++i)
        ++siz[find(i)];
    //初始化size
    int ans=0;
    for(register int i=1;i<=t;++i){
        int s=spget(),x=read()^ans,y=read()^ans;
        if(s){
            int k=read()^ans,l=lca(x,y);
            printf("%d\n",ans=ct.ask(root[x],root[y],root[l],root[fa[l][0]],k));
        }
        else merge(x,y);
    }
}