鏈接: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
*/