ST表、带权并查集

RMQ

Range Minimunm/Maximum Query

 f[i][j] :    以i为起点    长度为  2^{j} 的区间的最大值/最小值

最后是用2段区间去拼凑成一个我们要查询的区间,其中会有区间重复,所以使用ST表的前提条件就是要求,重复计算的区间不会对结果有影响,比如求:

最大值、最小值、 & 运算  、|运算 、    gcd

而且,区间是进行预处理的  O(nlogn)  ,查询 O(1)   ,    所以也不能对区间进行修改。

使用线段树也可以对区间进行操作,而且能进行更加复杂的信息维护,但单单进行查询的话,效率是没有ST表高的。

// problem :  

#include <bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int> PII;
#define pb push_back
const int N = 1e6 + 5;
typedef unsigned int ui;
unsigned int A, B, C, n, q, f[N][22], a[N];
inline unsigned int rng61() {
    A ^= A << 16;
    A ^= A >> 5;
    A ^= A << 1;
    unsigned int t = A;
    A = B;
    B = C;
    C ^= t ^ A;
    return C;
}

int main(){
    scanf("%d%d%u%u%u", &n, &q, &A, &B, &C);
    for (int i = 1; i <= n; i++) {
        a[i] = rng61();
        f[i][0] = a[i];
    }
    for (int j = 1; j <= 20; ++j) {
        for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
    }
    ui ans = 0;
    for (int i = 1; i <= q; i++) {
        unsigned int l = rng61() % n + 1, r = rng61() % n + 1;
        if (l > r) swap(l, r);
        // int x = log2(r - l + 1);
        int x = __lg(r - l + 1);

        ans ^= max(f[l][x], f[r - (1 <<x) + 1][x]);
    }
    printf("%u\n", ans);
}

带权并查集

 

// problem :  

#include <bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int> PII;
#define pb push_back
const int N = 2E5 + 5;
int f[N];
ll w[N];
int n, q;
int find(int x) {
    if(f[x] == x) return x;
    int p = f[x];
    find(p); // q
    /*
    旧的:       w[x] : a[x] - a[p]
     f[p] = q    w[p] : a[p] - a[q]
新的 f[x] = q    w[x] : a[x] - a[q]   更新的w[x]
    
    w[x] = a[x] - a[q] = a[x] - a[p] + a[p] - a[q]; 
    */
    w[x] = w[x] + w[p];
    return f[x] = f[p];
}
int main(){
    scanf("%d %d", &n, &q);
    for (int i = 1; i <= n; ++i) {
        f[i] = i;
        w[i] = 0;
    }
    ll t = 0;
    for (int i = 1; i <= q; ++i) {
        int ty, l, r;
        scanf("%d %d %d", &ty, &l, &r);
        l = (l + t) % n + 1;
        r = (r + t) % n + 1;
        if(ty == 2) {
            if(find(l) != find(r)) continue;
            printf("%lld\n", w[l] - w[r]);
            t = abs(w[l] - w[r]);
        } else {
            int x; scanf("%d", &x);
            if(find(l) == find(r)) continue;
            w[f[l]] = x - w[l] + w[r];
            f[f[l]] = f[r];
            /*
            w[f[l]] = a[f[l]] - a[f[r]]
            a[l] - a[r] = x
            w[l] = a[l] - a[f[l]],  w[r] = a[r] - a[f[r]]
            ==> w[f[l]] = a[l] - w[l] - (a[r] - w[r])
            */
        }
    }
    

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xingxg.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值