并查集 + splay启发式合并 - AcWing 1063 - 永无乡

并查集 + splay启发式合并 - AcWing 1063 - 永无乡

本题用并查集维护连通性,用splay支持在线查询第k大。为了使得splay能够完成合并操作,本题需要利用启发式的思想,即每次合并都将节点数少的splay的所有节点加入到节点数较多的splay中去。可以证明,splay的启发式合并的复杂度为\(O(nlogn)\)的。

// splay 启发式合并
#include <bits/stdc++.h>
using namespace std;

const int N = 500010;
int n,m,temp;
struct Node{
    int s[2],p,v,id;
    int size;
    void init(int _v,int _id,int _p){
        v = _v;
        id = _id;
        p = _p;
        size = 1;
    }
}tr[N];

int root[N],idx;

int f[N];
int find_f(int a){
    if(f[a]==a)return a;
    else return f[a] = find_f(f[a]);
}

inline int ws(int x){
    return tr[tr[x].p].s[1] == x;
}

void push_up(int x){
    tr[x].size = tr[tr[x].s[0]].size + tr[tr[x].s[1]].size + 1;
}

void rotate(int x){
    int y = tr[x].p;
    int z = tr[y].p;
    int k = ws(x);
    
    // modify z
    tr[z].s[ws(y)] = x;
    
    // modify y
    tr[y].p = x;
    tr[y].s[k] = tr[x].s[k^1];
    
    // modify m
    tr[tr[x].s[k^1]].p = y;
    
    // modify x
    tr[x].p = z;
    tr[x].s[k^1] = y;
    
    push_up(y);
    push_up(x);
}

void splay(int x,int k,int rt){
    while(tr[x].p != k){
        int y = tr[x].p;
        int z = tr[y].p;
        if(z != k){
            if(ws(x) ^ ws(y)){
                rotate(x);
            }else{
                rotate(y);
            }
        }
        rotate(x);
    }
    if(!k) root[rt] = x;
}

void insert(int v,int id,int rt){
    int u = root[rt], p = 0;
    while(u){
        p = u;
        u = tr[u].s[v > tr[u].v];
    }
    u = ++idx;
    if(p) tr[p].s[v > tr[p].v] = u;
    tr[u].init(v,id,p);
    splay(u,0,rt);
}


int get_k(int k,int rt){
    int u = root[rt];
    while(u){
        if(tr[tr[u].s[0]].size >= k){
            u = tr[u].s[0];
        }else if(tr[tr[u].s[0]].size + 1 == k){
            return tr[u].id;
        }else{
            k -= tr[tr[u].s[0]].size + 1;
            u = tr[u].s[1];
        }
    }
    return -1;
}


void dfs_insert(int node,int rt){
    if(tr[node].s[0]) dfs_insert(tr[node].s[0],rt);
    if(tr[node].s[1]) dfs_insert(tr[node].s[1],rt);
    insert(tr[node].v,tr[node].id,rt);
}


int main(){
    scanf("%d%d",&n,&m);
    // init
    for(int i = 1; i <= n; ++i){
        f[i] = root[i] = i;
        scanf("%d",&temp);
        tr[i].init(temp,i,0);
    }
    idx = n;
    
    // get edges
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        a = find_f(a);
        b = find_f(b);
        if(a != b){
            if(tr[root[a]].size > tr[root[b]].size){
                swap(a,b);
            }
            dfs_insert(root[a],b);
            f[a] = b;
        }
    }
    
    // op
    scanf("%d",&m);
    
    while(m--){
        char op[2];
        int a,b;
        scanf("%s%d%d",op,&a,&b);
        if(*op == 'B'){
            a = find_f(a);
            b = find_f(b);
            if(a != b){
                if(tr[root[a]].size > tr[root[b]].size){
                    swap(a,b);
                }
                dfs_insert(root[a],b);
                f[a] = b;
            }
        }else{
            a = find_f(a);
            if(tr[root[a]].size < b) puts("-1");
            else printf("%d\n",get_k(b,a));
        }
    }
    
    return 0;
}

上一篇:NOIP信息学1063:最大跨度值--信息学一本通(c++)


下一篇:才老师,我有九个问题!