牛客__[SDOI2013]森林

鏈接:https://ac.nowcoder.com/acm/problem/20577
來源:牛客網
 

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld

題目描述

小Z有一片森林,含有N個節點,每個節點上都有一個非負整數作爲權值。初始的時候,森林中有M條邊。
小Z希望執行T個操作,操作有兩類:

  1. Q x y k查詢點x到點y路徑上所有的權值中,第k小的權值是多少。此操作保證點x和點y連通,同時這兩個節點的路徑上至少有k個點。
  2. 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
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章