倍增算法和ST表

二进制的小问题

倍增问题

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

const int N = 200001;
const int LIMIT = 18;

int n, m;
int power;
vector<vector<int>> line(2 * N, vector<int>(3));  // 使用vector存储线段信息:编号、左边界、右边界
int stjump[2 * N][LIMIT];  // 稀疏表
int ans[N];  // 结果数组

int log2(int x) {
    int res = 0;
    while ((1 << res) <= (x >> 1)) {
        res++;
    }
    return res;
}

void build() {
    for (int i = 1; i <= n; i++) {
        if (line[i][1] > line[i][2]) {
            line[i][2] += m;
        }
    }
    // 使用 lambda 表达式进行排序
    sort(line.begin() + 1, line.begin() + n + 1, [](const vector<int>& a, const vector<int>& b) {
        return a[1] < b[1];
    });

    for (int i = 1; i <= n; i++) {
        line[i + n][0] = line[i][0];
        line[i + n][1] = line[i][1] + m;
        line[i + n][2] = line[i][2] + m;
    }
    int e = n << 1;  // 线段数量变成两倍
    for (int i = 1, arrive = 1; i <= e; i++) {
        while (arrive + 1 <= e && line[arrive + 1][1] <= line[i][2]) {
            arrive++;
        }
        stjump[i][0] = arrive;
    }

    for (int p = 1; p <= power; p++) {
        for (int i = 1; i <= e; i++) {
            stjump[i][p] = stjump[stjump[i][p - 1]][p - 1];
        }
    }
}

int jump(int i) {
    int aim = line[i][1] + m, cur = i, next, result = 0;
    for (int p = power; p >= 0; p--) {
        next = stjump[cur][p];
        if (next != 0 && line[next][2] < aim) {
            result += (1 << p);
            cur = next;
        }
    }
    return result + 1 + 1;
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> line[i][1] >> line[i][2];
        line[i][0] = i;
    }
    power = log2(n);
    build();
    for (int i = 1; i <= n; i++) {
        ans[line[i][0]] = jump(i);
    }
    for (int i = 1; i <= n; i++) {
        cout << (i > 1 ? " " : "") << ans[i];
    }
    cout << "\n";

    return 0;
}

st表维护区间长度

#include <iostream>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAXN = 50001;
const int LIMIT = 16; // 因为2的15次方是小于或等于50001的最大的2的幂

int arr[MAXN];
int lg2[MAXN]; // 更改变量名为lg2
int stmax[MAXN][LIMIT];
int stmin[MAXN][LIMIT];

void build(int n) {
    lg2[0] = -1;
    for (int i = 1; i <= n; i++) {
        lg2[i] = lg2[i >> 1] + 1; // 使用新的变量名lg2
        stmax[i][0] = arr[i];
        stmin[i][0] = arr[i];
    }
    for (int p = 1; p <= lg2[n]; p++) { // 使用新的变量名lg2
        for (int i = 1; i + (1 << p) - 1 <= n; i++) {
            stmax[i][p] = max(stmax[i][p - 1], stmax[i + (1 << (p - 1))][p - 1]);
            stmin[i][p] = min(stmin[i][p - 1], stmin[i + (1 << (p - 1))][p - 1]);
        }
    }
}

int query(int l, int r) {
    int p = lg2[r - l + 1]; // 使用新的变量名lg2
    int a = max(stmax[l][p], stmax[r - (1 << p) + 1][p]);
    int b = min(stmin[l][p], stmin[r - (1 << p) + 1][p]);
    return a - b;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); // 这可以帮助提升cin和cout的效率

    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    build(n);
    for (int i = 1, l, r; i <= m; i++) {
        cin >> l >> r;
        cout << query(l, r) << '\n';
    }

    return 0;
}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值