[HNOI2012]永无乡 线段树合并

[HNOI2012]永无乡

LG传送门

线段树合并练手题,写这篇博客只是为了给我的这篇文章找个板子题。

并查集维护连通性,对于不在同一个连通块内的合并操作每次直接合并两颗线段树,复杂度\(O(n \log n)\)

//written by newbiechd
#include <cstdio>
#define R register
#define I inline
using namespace std;
const int N = 100003;
int f[N], id[N], rt[N], T;
struct segtree {
    int p, q, s;
}e[N << 5];
I int find(int x) {
    R int r = x, y;
    while (f[r] ^ r)
        r = f[r];
    while (x ^ r)
        y = f[x], f[x] = r, x = y;
    return r;
}
void insert(int &k, int l, int r, int x) {
    k = ++T, ++e[k].s;
    if (l == r)
        return ;
    R int m = (l + r) >> 1;
    if (x <= m)
        insert(e[k].p, l, m, x);
    else
        insert(e[k].q, m + 1, r, x);
}
int merge(int k, int t, int l, int r) {
    if (!k)
        return t;
    if (!t)
        return k;
    e[k].s += e[t].s;
    if (l == r)
        return k;
    R int m = (l + r) >> 1;
    e[k].p = merge(e[k].p, e[t].p, l, m),
        e[k].q = merge(e[k].q, e[t].q, m + 1, r);
    return k;
}
int query(int k, int l, int r, int x) {
    if (l == r)
        return l;
    R int m = (l + r) >> 1, t = e[e[k].p].s;
    if (x <= t)
        return query(e[k].p, l, m, x);
    else
        return query(e[k].q, m + 1, r, x - t);
}
int main() {
    R int n, m, Q, i, x, y, z;
    R char opt[2];
    scanf("%d%d", &n, &m);
    for (i = 1; i <= n; ++i)
        f[i] = i, scanf("%d", &z), id[z] = i, insert(rt[i], 1, n, z);
    for (i = 1; i <= m; ++i)
        scanf("%d%d", &x, &y), x = find(x), y = find(y), f[y] = x,
            rt[x] = merge(rt[x], rt[y], 1, n);
    scanf("%d", &Q);
    for (i = 1; i <= Q; ++i) {
        scanf("%s%d%d", opt, &x, &y), x = find(x);
        if (opt[0] == 'B') {
            y = find(y);
            if (y ^ x)
                f[y] = x, merge(rt[x], rt[y], 1, n);
        }
        else
            if (y > e[rt[x]].s)
                printf("-1\n");
            else
                printf("%d\n", id[query(rt[x], 1, n, y)]);
    }
    return 0;
}

转载于:https://www.cnblogs.com/cj-chd/p/10433154.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值