【数据结构刷题记录】 [SDOI2013] 森林(启发式合并+主席树+树上差分思想)

坑点是输入的t是数据组数编号,不用初始化,不是t组数据。。
主席树是动态开点线段树,当然可以不用离散化!当然时间复杂度没啥区别,不过空间复杂度++

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <math.h>
#include <map>
#include <set>
#include <queue>

using namespace std;
#define endl '\n'
const int maxn = 2e5 + 5;
const int maxm = maxn << 1;
const int maxx = maxn * 100;
int head[maxn],nex[maxm],v[maxm],w[maxm],cnt,vis[maxn],dep[maxn];
void add(int x,int y){
    nex[++cnt] = head[x];
    head[x] = cnt;
    v[cnt] = y;
}
int n,m,q,rt[maxn],val[maxx],ls[maxx],rs[maxx],idx,f[maxn],sz[maxn];
int a[maxn],fa[maxn][21],rooter;
int build(int l,int r){
    int cur = ++idx;
    val[cur] = 0;
    if (l == r) return idx;
    int mid = l + r >> 1;
    ls[cur] = build(l,mid);
    rs[cur] = build(mid + 1,r);
    return cur;
}
int insert(int l,int r,int node,int p){
    int cur = ++idx;
    val[cur] = val[node] + 1,ls[cur] = ls[node],rs[cur] = rs[node];
    if (l == r) return cur;
    int mid = l + r >> 1;
    if (p <= mid) ls[cur] = insert(l,mid,ls[cur],p);
    else rs[cur] = insert(mid + 1,r,rs[cur],p);
    return cur;
}
int query(int l,int r,int rt1,int rt2,int rt3,int rt4,int k){
    if (l == r) return l;
    int cur = val[ls[rt1]] + val[ls[rt2]] - val[ls[rt3]] - val[ls[rt4]];
    int mid = l + r >> 1;
    if (cur >= k) return query(l,mid,ls[rt1],ls[rt2],ls[rt3],ls[rt4],k);
    return query(mid + 1,r,rs[rt1],rs[rt2],rs[rt3],rs[rt4],k - cur);
}
void dfs(int node,int father,int root){
    fa[node][0] = father;
    dep[node] = dep[father] + 1;
    f[node] = root;
    sz[root] ++;
    vis[node] = 1;
    for (int i = 1; i <= 20; ++i) {
        fa[node][i] = fa[fa[node][i - 1]][i - 1];
    }
    rt[node] = insert(1,1e9,rt[father],a[node]);
    for (int i = head[node]; i; i = nex[i]) {
        int to = v[i];
        if (to == father) continue;
        dfs(to,node,root);
    }
}
int lca(int x,int y){
    if (dep[x] < dep[y]) swap(x,y);
    for (int i = 20; i >= 0; --i) {
        if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
    }
    if (x == y) return x;
    for (int i = 20; i >= 0; --i) {
        if (fa[x][i] != fa[y][i]) x = fa[x][i],y = fa[y][i];
    }
    return fa[x][0];
}
int find(int x){
    if (x == f[x]) return x;
    return f[x] = find(f[x]);
}
void solve(){
    cin >> n >> m >> q;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    for (int i = 1; i <= m; ++i) {
        int x,y;
        cin >> x >> y;
        add(x,y);
        add(y,x);
    }
    for (int i = 1; i <= n; ++i) {
        if (!vis[i]) dfs(i,0,i);
    }
    int lastans = 0;
    while (q --){
        char c;
        int x,y,k;
        cin >> c >> x >> y;
        x ^= lastans;
        y ^= lastans;
        if (c == 'Q'){
            cin >> k;
            k ^= lastans;
            int lc = lca(x,y),lcfa = fa[lc][0];
            cout << (lastans = query(1,1e9,rt[x],rt[y],rt[lc],rt[lcfa],k)) << endl;
        }
        if (c == 'L'){
            int fx = find(x),fy = find(y);
            if (sz[fx] > sz[fy]){
                swap(x,y);
                swap(fx,fy);
            }
            add(x,y);
            add(y,x);
            dfs(x,y,fy);
        }

    }


}
signed main(){
    std::ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
#ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int T = 1;
    cin >> T;
    solve();

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值