链接:https://ac.nowcoder.com/acm/problem/20577
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
小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.
输入描述:
第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1<=testcase<=20。 第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。 第三行包含N个非负整数表示 N个节点上的权值。 接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边。 接下来 T行,每行描述一个操作,格式为”Q x y k“或者”L x y “,其含义见题目描述部分。
输出描述:
对于每一个第一类操作,输出一个非负整数表示答案。
示例1
输入
复制
1 8 4 8 1 1 2 2 3 3 4 4 4 7 1 8 2 4 2 1 Q 8 7 3 Q 3 5 1 Q 10 0 0 L 5 4 L 3 2 L 0 7 Q 9 2 5 Q 6 1 6
输出
复制
2 2 1 4 2
备注:
lca和主席树,先按每条链去建主席树,然后再利用lca求答案
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+9;
int t,n,m,op,num,ans;
int a[maxn],h[maxn],who[maxn];
int f[maxn],sz[maxn];
int tot,cur,head[maxn],vis[maxn];
int pre[maxn][50],dep[maxn];
int rt[maxn],sum[maxn*40],lson[maxn*40],rson[maxn*40];
struct Edge{
int v,next;
}edge[maxn*2];
void init(){
tot=0; cur=0; ans=0;
memset(head,-1,sizeof(head));
}
void addEdge(int u,int v){
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
int Find(int x){
return f[x]==x?x:f[x]=Find(f[x]);
}
void link(int &u,int &v){
u^=ans,v^=ans;
addEdge(u,v),addEdge(v,u);
int x=Find(u),y=Find(v);
if(sz[x]>sz[y])swap(x,y),swap(u,v);
f[x]=y; sz[y]+=sz[x];
}
void update(int pre,int &now,int l,int r,int L){
sum[now=++cur]=sum[pre]+1;
lson[now]=lson[pre],rson[now]=rson[pre];
if(l==r)return;
int mid=(l+r)>>1;
if(L<=mid)update(lson[pre],lson[now],l,mid,L);
else update(rson[pre],rson[now],mid+1,r,L);
}
void dfs(int u,int fa){
vis[u]=1,pre[u][0]=fa,dep[u]=dep[fa]+1;
update(rt[fa],rt[u],1,num,who[u]);
for(int i=1;i<=18;i++){
pre[u][i]=pre[pre[u][i-1]][i-1];
}
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==fa)continue;
dfs(v,u);
}
}
int LCA(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=18;i>=0;i--){
if(dep[pre[u][i]]>=dep[v]){
u=pre[u][i];
}
}
if(u==v)return u;
for(int i=18;i>=0;i--){
if(pre[u][i]!=pre[v][i]){
u=pre[u][i];
v=pre[v][i];
}
}
return pre[u][0];
}
void query(int upre,int vpre,int u,int v,int l,int r,int k){
if(l==r){ans=h[l];return;}
int Sum=sum[lson[u]]-sum[lson[upre]]+sum[lson[v]]-sum[lson[vpre]];
int mid=(l+r)>>1;
if(Sum>=k)query(lson[upre],lson[vpre],lson[u],lson[v],l,mid,k);
else query(rson[upre],rson[vpre],rson[u],rson[v],mid+1,r,k-Sum);
}
void solve(int u,int v,int k){
u^=ans,v^=ans,k^=ans;
int lca=LCA(u,v);
// printf("lca %d\n",lca);
query(rt[pre[lca][0]],rt[lca],rt[u],rt[v],1,num,k);
printf("%d\n",ans);
}
int main(){
scanf("%d",&t);
init();
scanf("%d %d %d",&n,&m,&op);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
h[i]=a[i];
}
sort(h+1,h+1+n);
num=unique(h+1,h+1+n)-h-1;
for(int i=1;i<=n;i++){
who[i]=lower_bound(h+1,h+1+num,a[i])-h;
}
for(int i=1;i<=n;i++) f[i]=i,sz[i]=1;
int u,v;
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
link(u,v);
}
for(int i=1;i<=n;i++){
if(!vis[Find(i)])dfs(Find(i),0);
}
char s[10];
for(int i=1;i<=op;i++){
scanf("%s",s);
if(s[0]=='Q'){
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
solve(u,v,k);
}
else{
int u,v;
scanf("%d%d",&u,&v);
link(u,v);
dfs(u,v);
}
}
return 0;
}
/*
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3
Q 3 5 1
Q 10 0 0
L 5 4
L 3 2
L 0 7
Q 9 2 5
Q 6 1 6
*/