区间(树上)第k小(大)问题
P3834 【模板】可持久化线段树 1(主席树)
静态区间第k小。
主席树模板题
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,x,y,k; 4 struct node 5 { 6 int l,r,sum; 7 }num[3400000]; 8 int head[200050],a[200050],v[200050],pos[200050],w[200050],cnt,tot; 9 bool cmp(int x,int y) 10 { 11 return a[x]<a[y]; 12 } 13 void build(int l,int r,int &u) 14 { 15 u=++tot; 16 num[u].sum=0; 17 if(l==r) 18 return ; 19 int mid=(l+r)>>1; 20 build(l,mid,num[u].l); 21 build(mid+1,r,num[u].r); 22 } 23 void update(int l,int r,int val,int las,int &u) 24 { 25 u=++tot; 26 num[u].l=num[las].l; 27 num[u].r=num[las].r; 28 num[u].sum=num[las].sum+1; 29 if(l==r) 30 return ; 31 int mid=(l+r)>>1; 32 if(val<=mid) 33 update(l,mid,val,num[las].l,num[u].l); 34 else 35 update(mid+1,r,val,num[las].r,num[u].r); 36 } 37 int calc(int l,int r,int las,int u,int tk) 38 { 39 if(l==r) 40 return l; 41 int mid=(l+r)>>1; 42 int tmp=num[num[u].l].sum-num[num[las].l].sum; 43 if(tmp>=tk) 44 return calc(l,mid,num[las].l,num[u].l,tk); 45 else 46 return calc(mid+1,r,num[las].r,num[u].r,tk-tmp); 47 } 48 int main() 49 { 50 scanf("%d%d",&n,&m); 51 for(int i=1;i<=n;i++) 52 { 53 scanf("%d",&a[i]); 54 pos[i]=i; 55 } 56 sort(pos+1,pos+n+1,cmp); 57 for(int i=1;i<=n;i++) 58 { 59 if(a[pos[i]]!=a[pos[i-1]]||i==1) 60 w[++cnt]=a[pos[i]]; 61 v[pos[i]]=cnt; 62 } 63 build(1,cnt,head[0]); 64 for(int i=1;i<=n;i++) 65 update(1,cnt,v[i],head[i-1],head[i]); 66 while(m--) 67 { 68 scanf("%d%d%d",&x,&y,&k); 69 printf("%d\n",w[calc(1,cnt,head[x-1],head[y],k)]); 70 } 71 return 0; 72 }
离线的区间第k小当然也可以套整体二分。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,tot,cnt; 4 int ans[200050],c[200050],L=1e9,R=-1e9; 5 int pos[200050],lis[200050]; 6 void calc_add(int u,int v) 7 { 8 while(u<=n) 9 { 10 c[u]+=v; 11 u+=u&-u; 12 } 13 } 14 int calc_ask(int u) 15 { 16 int sum=0; 17 while(u) 18 { 19 sum+=c[u]; 20 u-=u&-u; 21 } 22 return sum; 23 } 24 struct node 25 { 26 int opt,x,l,r,val; 27 }t[400050],tl[400050],tr[400050]; 28 bool cmp (int a,int b) 29 { 30 return t[a].val<t[b].val; 31 } 32 void calc(int l,int r,int x,int y) 33 { 34 if(x==y) 35 { 36 for(int i=l;i<=r;++i) 37 if(t[i].opt) 38 ans[t[i].x]=lis[x]; 39 return ; 40 } 41 int mid=(x+y)>>1; 42 int totl=0,totr=0; 43 for(int i=l;i<=r;++i) 44 { 45 if(!t[i].opt) 46 { 47 if(t[i].val<=mid) 48 { 49 calc_add(t[i].x,1); 50 tl[++totl]=t[i]; 51 } 52 else 53 tr[++totr]=t[i]; 54 } 55 else 56 { 57 int tmp=calc_ask(t[i].r)-calc_ask(t[i].l-1); 58 if(tmp>=t[i].val) 59 tl[++totl]=t[i]; 60 else 61 { 62 t[i].val-=tmp; 63 tr[++totr]=t[i]; 64 } 65 } 66 } 67 for(int i=1;i<=totl;++i) 68 if(!tl[i].opt) 69 calc_add(tl[i].x,-1); 70 for(int i=1;i<=totl;++i) t[l+i-1]=tl[i]; 71 for(int i=1;i<=totr;++i) t[l+totl+i-1]=tr[i]; 72 calc(l,l+totl-1,x,mid); 73 calc(l+totl,r,mid+1,y); 74 } 75 int main() 76 { 77 scanf("%d%d",&n,&m);tot=n; 78 for(int i=1;i<=tot;++i) 79 { 80 scanf("%d",&t[i].val); 81 t[i].x=i; pos[i]=i; 82 }tot=n+m; 83 sort(pos+1,pos+n+1,cmp); 84 for(int i=1;i<=n;++i) 85 { 86 lis[i]=t[pos[i]].val; 87 t[pos[i]].val=i; 88 } 89 for(int i=n+1;i<=tot;++i) 90 { 91 scanf("%d%d%d",&t[i].l,&t[i].r,&t[i].val); 92 t[i].x=i-n; t[i].opt=1; 93 } 94 calc(1,tot,1,n); 95 for(int i=1;i<=m;++i) 96 printf("%d\n",ans[i]); 97 return 0; 98 }
P2633 Count on a tree
静态树上路径第k小。
沿用静态区间第k小的做法,每个节点用一棵线段树维护从根节点到当前节点路径中的节点权值。
查询时只要找到 lca 就可以变成两条深度递增的链了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,x,y,ans,tot; 4 int cnt,k; 5 int w[100050],lca; 6 int val[100050]; 7 int pos[100050]; 8 int rnk[100050]; 9 int head[200050]; 10 int son[2000050][2]; 11 int root[100050]; 12 int sum[2000050]; 13 int fath[100050]; 14 int nex[200050],ver[200050]; 15 int f[100050][20],deep[100050]; 16 bool cmp(int x,int y) 17 { 18 return val[x]<val[y]; 19 } 20 void calc_build(int l,int r,int val,int u,int &v) 21 { 22 v=++cnt; 23 sum[v]=sum[u]+1; 24 if(l==r) 25 return ; 26 son[v][0]=son[u][0]; 27 son[v][1]=son[u][1]; 28 int mid=(l+r)>>1; 29 if(val<=mid) 30 calc_build(l,mid,val,son[u][0],son[v][0]); 31 else 32 calc_build(mid+1,r,val,son[u][1],son[v][1]); 33 } 34 int calc_ask(int l,int r,int a,int b,int c,int d) 35 { 36 if(l==r) 37 return l; 38 int mid=(l+r)>>1; 39 int tmp=sum[son[a][0]]+sum[son[b][0]]-sum[son[c][0]]-sum[son[d][0]]; 40 if(tmp>=k) 41 return calc_ask(l,mid,son[a][0],son[b][0],son[c][0],son[d][0]); 42 k-=tmp; 43 return calc_ask(mid+1,r,son[a][1],son[b][1],son[c][1],son[d][1]); 44 } 45 void add(int x,int y) 46 { 47 nex[++tot]=head[x]; 48 head[x]=tot; 49 ver[tot]=y; 50 } 51 void dfs(int u,int fa) 52 { 53 calc_build(1,n,rnk[u],root[fa],root[u]); 54 fath[u]=fa; 55 deep[u]=deep[fa]+1;f[u][0]=fa; 56 for(int k=1;k<=18;++k) 57 f[u][k]=f[f[u][k-1]][k-1]; 58 for(int i=head[u];i;i=nex[i]) 59 if(ver[i]!=fa) 60 dfs(ver[i],u); 61 } 62 int calc_lca(int a,int b) 63 { 64 if(deep[a]<deep[b]) 65 swap(a,b); 66 for(int i=18;i>=0;--i) 67 if(deep[f[a][i]]>=deep[b]) 68 a=f[a][i]; 69 if(a==b) 70 return a; 71 for(int i=18;i>=0;--i) 72 if(f[a][i]!=f[b][i]) 73 { 74 a=f[a][i]; 75 b=f[b][i]; 76 } 77 return f[a][0]; 78 } 79 int main() 80 { 81 scanf("%d%d",&n,&m); 82 for(int i=1;i<=n;++i) 83 { 84 scanf("%d",&val[i]); 85 pos[i]=i; 86 } 87 sort(pos+1,pos+n+1,cmp); 88 for(int i=1;i<=n;++i) 89 { 90 rnk[pos[i]]=i; 91 w[i]=val[pos[i]]; 92 } 93 for(int i=1;i<n;++i) 94 { 95 scanf("%d%d",&x,&y); 96 add(x,y); add(y,x); 97 } 98 dfs(1,0); 99 while(m--) 100 { 101 scanf("%d%d%d",&x,&y,&k); 102 x^=ans; 103 lca=calc_lca(x,y); 104 ans=calc_ask(1,n,root[x],root[y],root[lca],root[fath[lca]]); 105 ans=w[ans]; 106 printf("%d\n",ans); 107 } 108 return 0; 109 }
P3380 【模板】二逼平衡树(树套树)
动态区间第k小。
这次是树套树的模板了。树状数组套权值线段树。位置套数值(当然也可以反着来,但在此题并没有优势)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=40000000; 4 char c; 5 int n,m,cnt; 6 int sum[N]; 7 int val[100050]; 8 int root[100050]; 9 int t[200050],tot; 10 int son[N][2]; 11 int tl[100050]; 12 int tr[100050]; 13 struct node 14 { 15 int opt,l,r,pos,v; 16 }num[100050]; 17 void modify(int &u,int l,int r,int pos,int v) 18 { 19 if(!u) u=++cnt; 20 sum[u]+=v; 21 if(l==r) return ; 22 int mid=(l+r)>>1; 23 if(pos<=mid) modify(son[u][0],l,mid,pos,v); 24 else modify(son[u][1],mid+1,r,pos,v); 25 } 26 void calc_modify(int u,int v) 27 { 28 int tmp=lower_bound(t+1,t+tot+1,val[u])-t; 29 for(int i=u;i<=n;i+=i&-i) modify(root[i],1,tot,tmp,v); 30 } 31 int ask(int l,int r,int v) 32 { 33 if(l==r) return l; 34 int mid=(l+r)>>1,s=0; 35 for(int i=1;i<=tr[0];++i) s+=sum[son[tr[i]][0]]; 36 for(int i=1;i<=tl[0];++i) s-=sum[son[tl[i]][0]]; 37 if(v<=s) 38 { 39 for(int i=1;i<=tr[0];++i) tr[i]=son[tr[i]][0]; 40 for(int i=1;i<=tl[0];++i) tl[i]=son[tl[i]][0]; 41 return ask(l,mid,v); 42 } 43 else 44 { 45 for(int i=1;i<=tr[0];++i) tr[i]=son[tr[i]][1]; 46 for(int i=1;i<=tl[0];++i) tl[i]=son[tl[i]][1]; 47 return ask(mid+1,r,v-s); 48 } 49 } 50 int calc_ask(int l,int r,int v) 51 { 52 tl[0]=tr[0]=0; 53 for(int i=r;i;i-=i&-i) tr[++tr[0]]=root[i]; 54 for(int i=l-1;i;i-=i&-i) tl[++tl[0]]=root[i]; 55 return ask(1,tot,v); 56 } 57 int rnk(int l,int r,int pos) 58 { 59 int s=0; 60 if(r<=pos) 61 { 62 for(int i=1;i<=tr[0];++i) s+=sum[tr[i]]; 63 for(int i=1;i<=tl[0];++i) s-=sum[tl[i]]; 64 return s; 65 } 66 int mid=(l+r)>>1; 67 if(pos>mid) 68 { 69 for(int i=1;i<=tr[0];++i) s+=sum[son[tr[i]][0]],tr[i]=son[tr[i]][1]; 70 for(int i=1;i<=tl[0];++i) s-=sum[son[tl[i]][0]],tl[i]=son[tl[i]][1]; 71 return s+rnk(mid+1,r,pos); 72 } 73 else if(pos>=l) 74 { 75 for(int i=1;i<=tr[0];++i) tr[i]=son[tr[i]][0]; 76 for(int i=1;i<=tl[0];++i) tl[i]=son[tl[i]][0]; 77 return rnk(l,mid,pos); 78 } 79 else return 0; 80 81 } 82 int calc_rnk(int l,int r,int v) 83 { 84 tl[0]=tr[0]=0; 85 for(int i=r;i;i-=i&-i) tr[++tr[0]]=root[i]; 86 for(int i=l-1;i;i-=i&-i) tl[++tl[0]]=root[i]; 87 return rnk(1,tot,v); 88 } 89 int main() 90 { 91 scanf("%d%d",&n,&m); 92 for(int i=1;i<=n;++i) 93 { 94 scanf("%d",&val[i]); 95 t[++tot]=val[i]; 96 } 97 for(int i=1;i<=m;++i) 98 { 99 scanf("%d",&num[i].opt); 100 if(num[i].opt==3) scanf("%d%d",&num[i].pos,&num[i].v); 101 else scanf("%d%d%d",&num[i].l,&num[i].r,&num[i].v); 102 if(num[i].opt!=2) t[++tot]=num[i].v; 103 } 104 sort(t+1,t+tot+1); 105 tot=unique(t+1,t+tot+1)-t-1; 106 for(int i=1;i<=n;++i) 107 calc_modify(i,1); 108 for(int i=1;i<=m;++i) 109 { 110 if(num[i].opt==1) printf("%d\n",calc_rnk(num[i].l,num[i].r,lower_bound(t+1,t+tot+1,num[i].v)-t-1)+1); 111 else if(num[i].opt==2) printf("%d\n",t[calc_ask(num[i].l,num[i].r,num[i].v)]); 112 else if(num[i].opt==3) 113 { 114 calc_modify(num[i].pos,-1); 115 val[num[i].pos]=num[i].v; 116 calc_modify(num[i].pos,1); 117 } 118 else if(num[i].opt==4) 119 { 120 int tmp=calc_rnk(num[i].l,num[i].r,lower_bound(t+1,t+tot+1,num[i].v)-t-1); 121 if(tmp==0) printf("-2147483647\n"); 122 else printf("%d\n",t[calc_ask(num[i].l,num[i].r,tmp)]); 123 } 124 else 125 { 126 int tmp=calc_rnk(num[i].l,num[i].r,lower_bound(t+1,t+tot+1,num[i].v)-t); 127 if(tmp==num[i].r-num[i].l+1) printf("2147483647\n"); 128 else printf("%d\n",t[calc_ask(num[i].l,num[i].r,tmp+1)]); 129 } 130 } 131 return 0; 132 }
P4175 [CTSC2008]网络管理
动态树上路径第k大。
用 dfs 序将其转化为动态区间第 k 小。关键的是 dfs 序的应用。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,tot,ans; 4 int x,y,opt,cnt; 5 int f[100050][20]; 6 int deep[100050]; 7 int head[100050]; 8 int nex[200050]; 9 int ver[200050]; 10 int siz[100050]; 11 int val[100050]; 12 int root[100050]; 13 int sum[20000050]; 14 int son[20000050][2]; 15 int I[100050]; 16 int O[100050]; 17 int t[2000],top; 18 int g[2000]; 19 void add(int x,int y) 20 { 21 nex[++tot]=head[x]; 22 ver[tot]=y; 23 head[x]=tot; 24 } 25 void dfs(int u,int fa) 26 { 27 deep[u]=deep[fa]+1; f[u][0]=fa; 28 for(int k=1;k<=17;++k) 29 f[u][k]=f[f[u][k-1]][k-1]; 30 I[u]=++tot; siz[u]=1; 31 for(int i=head[u];i;i=nex[i]) 32 if(ver[i]!=fa) 33 { 34 dfs(ver[i],u); 35 siz[u]+=siz[ver[i]]; 36 } 37 O[u]=I[u]+siz[u]; 38 } 39 int lca(int x,int y) 40 { 41 if(deep[x]<deep[y]) swap(x,y); 42 for(int i=17;i>=0;--i) 43 if(deep[f[x][i]]>=deep[y]) 44 x=f[x][i]; 45 if(x==y) return x; 46 for(int i=17;i>=0;--i) 47 if(f[x][i]!=f[y][i]) 48 { 49 x=f[x][i]; 50 y=f[y][i]; 51 } 52 return f[x][0]; 53 } 54 void add(int &u,int l,int r,int pos,int val) 55 { 56 if(!u) u=++tot; 57 sum[u]+=val; 58 if(l==r) return ; 59 int mid=(l+r)>>1; 60 if(pos<=mid) add(son[u][0],l,mid,pos,val); 61 else add(son[u][1],mid+1,r,pos,val); 62 } 63 void calc_add(int x,int y,int val) 64 { 65 for(int i=x;i<=n;i+=i&-i) 66 add(root[i],0,1e8,y,val); 67 } 68 int ask(int l,int r) 69 { 70 if(l==r) return l; 71 int tmp=0; int mid=(l+r)>>1; 72 for(int i=1;i<=top;++i) 73 tmp+=sum[son[t[i]][1]]*g[i]; 74 if(opt>tmp) 75 { 76 opt-=tmp; 77 for(int i=1;i<=top;++i) 78 t[i]=son[t[i]][0]; 79 return ask(l,mid); 80 } 81 else 82 { 83 for(int i=1;i<=top;++i) 84 t[i]=son[t[i]][1]; 85 return ask(mid+1,r); 86 } 87 } 88 void calc_ask(int u,int pos) 89 { 90 for(int i=u;i;i-=i&-i) 91 if(root[i]) 92 { 93 t[++top]=root[i]; 94 g[top]=pos; 95 } 96 } 97 int main() 98 { 99 scanf("%d%d",&n,&m); 100 for(int i=1;i<=n;++i) 101 scanf("%d",&val[i]); 102 for(int i=1;i<n;++i) 103 { 104 scanf("%d%d",&x,&y); 105 add(x,y); add(y,x); 106 } 107 tot=0; dfs(1,0); tot=0; 108 for(int i=1;i<=n;++i) 109 { 110 calc_add(I[i],val[i],1); 111 calc_add(O[i],val[i],-1); 112 } 113 while(m--) 114 { 115 scanf("%d%d%d",&opt,&x,&y); 116 if(opt==0) 117 { 118 calc_add(I[x],val[x],-1); 119 calc_add(O[x],val[x],1); 120 val[x]=y; 121 calc_add(I[x],val[x],1); 122 calc_add(O[x],val[x],-1); 123 } 124 else 125 { 126 int LCA=lca(x,y); 127 if(deep[x]+deep[y]-deep[LCA]*2+1<opt) 128 { 129 printf("invalid request!\n"); 130 continue ; 131 } 132 top=0; 133 calc_ask(I[x],1); 134 calc_ask(I[y],1); 135 calc_ask(I[LCA],-1); 136 calc_ask(I[f[LCA][0]],-1); 137 printf("%d\n",ask(0,1e8)); 138 } 139 } 140 return 0; 141 }
区间修改与区间查询。
树套树的话,常数似乎会比较大。所以我写的是整体二分。
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,tot; 4 int ans[100050]; 5 struct node 6 { 7 int opt,l,r,pos; 8 long long val; 9 }num[100050],tl[100050],tr[100050]; 10 long long c1[50050],c2[50050]; 11 void add(int u,int v) 12 { 13 for(int i=u;i<=n;i+=i&-i) 14 c1[i]+=v,c2[i]+=v*u; 15 } 16 long long ask(int u) 17 { 18 long long tmp=0; 19 for(int i=u;i;i-=i&-i) 20 tmp+=(u+1)*c1[i]-c2[i]; 21 return tmp; 22 } 23 void calc_add(int l,int r,int v) 24 { 25 add(l,v); add(r+1,-v); 26 } 27 long long calc_ask(int l,int r) 28 { 29 return ask(r)-ask(l-1); 30 } 31 void calc(int L,int R,int l,int r) 32 { 33 if(l==r) 34 { 35 for(int i=L;i<=R;++i) ans[num[i].pos]=l; 36 return ; 37 } 38 int mid=(l+r)>>1; 39 bool fl=0,fr=0; 40 int topl=0,topr=0; 41 for(int i=L;i<=R;++i) 42 if(num[i].opt==1) 43 { 44 if(num[i].val<=mid) 45 tl[++topl]=num[i]; 46 else 47 { 48 calc_add(num[i].l,num[i].r,1); 49 tr[++topr]=num[i]; 50 } 51 } 52 else 53 { 54 long long tmp=calc_ask(num[i].l,num[i].r); 55 if(num[i].val>tmp) 56 { 57 num[i].val-=tmp; 58 fl=true; 59 tl[++topl]=num[i]; 60 } 61 else 62 { 63 fr=true; 64 tr[++topr]=num[i]; 65 } 66 } 67 for(int i=L;i<=R;++i) 68 if(num[i].opt==1&&num[i].val>mid) 69 calc_add(num[i].l,num[i].r,-1); 70 for(int i=1;i<=topl;++i) num[L+i-1]=tl[i]; 71 for(int i=1;i<=topr;++i) num[L+topl+i-1]=tr[i]; 72 if(fl) calc(L,L+topl-1,l,mid); 73 if(fr) calc(L+topl,R,mid+1,r); 74 } 75 int main() 76 { 77 scanf("%d%d",&n,&m); 78 for(int i=1;i<=m;++i) 79 { 80 scanf("%d%d%d%lld",&num[i].opt,&num[i].l,&num[i].r,&num[i].val); 81 if(num[i].opt==2) num[i].pos=++tot; 82 } 83 calc(1,m,-n,n); 84 for(int i=1;i<=tot;++i) printf("%d\n",ans[i]); 85 return 0; 86 }
P3302 [SDOI2013]森林
支持动态合并的树上路径第k小。(肯定在线啊。
关于集合的合并有一种方式叫做启发式合并,这样会在静态的基础上多个log。
1 #include<bits/stdc++.h> 2 using namespace std; 3 char opt; 4 int n,m,T,s,cnt; 5 int x,y,z,a,b,ans; 6 int val[100050]; 7 int t[100050],top; 8 int f[100050][18]; 9 int deep[100050]; 10 int root[100050]; 11 int sum[40000050]; 12 int son[40000050][2]; 13 int head[100050],tot; 14 int nex[200050],ver[200050]; 15 int siz[100050],anc[100050]; 16 int find(int u) 17 { 18 return anc[u]==u? u:anc[u]=find(anc[u]); 19 } 20 void add(int x,int y) 21 { 22 nex[++tot]=head[x]; 23 ver[tot]=y; 24 head[x]=tot; 25 } 26 void build(int &u,int v,int l,int r,int pos) 27 { 28 u=++cnt; 29 sum[u]=sum[v]+1; 30 if(l==r) return ; 31 son[u][0]=son[v][0]; 32 son[u][1]=son[v][1]; 33 int mid=(l+r)>>1; 34 if(pos<=mid) build(son[u][0],son[v][0],l,mid,pos); 35 else build(son[u][1],son[v][1],mid+1,r,pos); 36 } 37 void dfs(int u,int fa) 38 { 39 deep[u]=deep[fa]+1; f[u][0]=fa; 40 for(int k=1;k<=17;++k) 41 f[u][k]=f[f[u][k-1]][k-1]; 42 build(root[u],root[fa],1,top,val[u]); 43 for(int i=head[u];i;i=nex[i]) 44 if(ver[i]!=fa) 45 dfs(ver[i],u); 46 } 47 int lca(int x,int y) 48 { 49 if(deep[x]<deep[y]) swap(x,y); 50 for(int i=17;i>=0;--i) 51 if(deep[f[x][i]]>=deep[y]) 52 x=f[x][i]; 53 if(x==y) return x; 54 for(int i=17;i>=0;--i) 55 if(f[x][i]!=f[y][i]) 56 { 57 x=f[x][i]; 58 y=f[y][i]; 59 } 60 return f[x][0]; 61 } 62 void calc_add(int x,int y) 63 { 64 add(x,y); add(y,x); 65 int fx=find(x); 66 int fy=find(y); 67 if(siz[x]<siz[y]) 68 { 69 swap(x,y); 70 swap(fx,fy); 71 } 72 anc[fy]=fx; siz[fx]+=siz[fy]; 73 dfs(y,x); 74 } 75 int calc_ask(int l,int r) 76 { 77 if(l==r) return l; 78 int tmp=sum[son[x][0]]+sum[son[y][0]]; 79 tmp-=sum[son[a][0]]+sum[son[b][0]]; 80 int mid=(l+r)>>1; 81 if(z<=tmp) 82 { 83 x=son[x][0]; y=son[y][0]; 84 a=son[a][0]; b=son[b][0]; 85 return calc_ask(l,mid); 86 } 87 else 88 { 89 z-=tmp; 90 x=son[x][1]; y=son[y][1]; 91 a=son[a][1]; b=son[b][1]; 92 return calc_ask(mid+1,r); 93 } 94 } 95 int main() 96 { 97 scanf("%d%d%d%d",&s,&n,&m,&T); 98 for(int i=1;i<=n;++i) 99 { 100 scanf("%d",&val[i]); 101 t[i]=val[i]; 102 anc[i]=i; 103 siz[i]=1; 104 } 105 sort(t+1,t+n+1); 106 top=unique(t+1,t+n+1)-t-1; 107 for(int i=1;i<=n;++i) 108 val[i]=lower_bound(t+1,t+top+1,val[i])-t; 109 while(m--) 110 { 111 scanf("%d%d",&x,&y); 112 add(x,y); add(y,x); 113 int fx=find(x); 114 int fy=find(y); 115 anc[fy]=fx; 116 siz[fx]+=siz[fy]; 117 } 118 for(int i=1;i<=n;++i) 119 if(!root[i]) 120 dfs(i,0); 121 while(T--) 122 { 123 scanf(" %c%d%d",&opt,&x,&y); 124 x^=ans; y^=ans; 125 if(opt=='Q') 126 { 127 scanf("%d",&z); 128 z^=ans; 129 a=lca(x,y); 130 b=f[a][0]; 131 x=root[x]; y=root[y]; 132 a=root[a]; b=root[b]; 133 ans=t[calc_ask(1,top)]; 134 printf("%d\n",ans); 135 } 136 else 137 calc_add(x,y); 138 } 139 return 0; 140 }