P3224 [HNOI2012] 永无乡

题面大意:

给你\(~n~\)个点,每个点有一个唯一的权值,刚开始有\(~m~\)条边,接下来有\(~q~\)次操作,分为两种,第一种是在两个点之间连上一条边,第二种是询问某一个节点所在联通块内第\(~k~\)小的权值的节点编号是多少。\(%\)

Solution:

这题对于我来说还是太困难了,所以看完题就看了题解。理解为这样的一个维护过程,首先需要你动态开点的维护一个权值线段树,接下来,就是维护操作,对于查询,在每棵线段树上维护$k $小值即可,对于连边,用并查集维护并判断是否在一个联通块内,然后对两棵线段树进行合并操作,具体实现可以参考下面代码。

#include <bits/stdc++.h>
#define IOS ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
using namespace std;
typedef long long ll;
int n, m, q, id, rk[200005], fa[200005], p[200005], ans[200005];
int fnd(int x)
{
    return (fa[x] == x ? x : fa[x] = fnd(fa[x]));
}
struct node
{
    int l, r;
    int sum, idl, idr;
};
node tree[5000005];
int insert(int rank, int l, int r)
{
    int rt = ++ id;
    tree[rt] = {l, r, 1, 0, 0};
    if(l == r) return rt;
    int mid = l + r >> 1;
    if(rank <= mid) tree[rt].idl = insert(rank, l, mid);
    if(rank > mid) tree[rt].idr = insert(rank, mid + 1, r);
    return rt;
}
int unite(int ql, int qr, int l, int r)
{
    if(!ql) return qr;
    if(!qr) return ql;
    int mid = l + r >> 1,  rt = ++ id;
    tree[rt] = {l, r, tree[ql].sum + tree[qr].sum, unite(tree[ql].idl, tree[qr].idl, l, mid), unite(tree[ql].idr, tree[qr].idr, mid + 1, r)};
    return rt;
}
int query(int x, int k)
{
    if(tree[x].sum < k) return -1;
    if(tree[x].l == tree[x].r) return ans[tree[x].l];
    if(tree[tree[x].idl].sum >= k) return query(tree[x].idl, k);
    return query(tree[x].idr, k - tree[tree[x].idl].sum);
}
int main()
{
    IOS;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) fa[i] = i;
    for(int i = 1; i <= n; i ++) cin >> rk[i], p[i] = insert(rk[i], 1, n), ans[rk[i]] = i;
    for(int i = 1; i <= m; i ++)
    {
        int u, v;
        cin >> u >> v;
        int rtu = fnd(u), rtv = fnd(v);
        if(rtu != rtv) fa[rtu] = rtv, p[rtv] = unite(p[rtu], p[rtv], 1, n);
    }
    cin >> q;
    for(int i = 1; i <= q; i ++)
    {
        char opt;
        int u, v;
        cin >> opt >> u >> v;
        if(opt == 'Q') cout << query(p[fnd(u)], v) << endl;
        else 
        {
            int rtu = fnd(u), rtv = fnd(v);
            if(rtu != rtv) fa[rtu] = rtv, p[rtv] = unite(p[rtu], p[rtv], 1, n);
        }
    }
    return 0;
}
posted @ 2025-10-29 00:01  LTC_Augenstern  阅读(5)  评论(0)    收藏  举报