倍增&ST算法
倍增
倍增:预处理的就是每个点走 2^i 步的结果
通过预处理go[][]数组,拼凑出需要走的操作数
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 10; // 节点数
const int LOG = 20; // log2(N) 的上界,保证够大
int go[N][LOG]; // go[x][i] 表示从 x 出发走 2^i 步到哪里
int main() {
int n = 6; // 节点数
// 初始化 go[x][0] (走 1 步)
// 链: 1->2->3->4->5->6->0 (0 表示 null/不存在)
go[1][0] = 2;
go[2][0] = 3;
go[3][0] = 4;
go[4][0] = 5;
go[5][0] = 6;
go[6][0] = 0; // null
// 预处理倍增表
for (int j = 1; j < LOG; j++) {//20*n
for (int x = 1; x <= n; x++) {
int mid = go[x][j-1];
if (mid) go[x][j] = go[mid][j-1]; // 跳 2^(j-1) + 2^(j-1)
else go[x][j] = 0;
}
}
// 示例查询:从 1 出发走 5 步到哪里
int start = 2, k = 3;
int cur = start;
for (int j = 0; j < LOG; j++) {
if (k & (1 << j)) { // 如果 k 的二进制有第 j 位
cur = go[cur][j];
if (!cur) break; // 提前终止
}
}
cout << "从 " << start << " 出发走 " << k << " 步,到达 " << cur << endl;
return 0;
}
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 1;
int n, m;
struct Node {
int id, L, R;
bool operator< (const Node b) const {
return L < b.L;
}
};
Node w[N * 2];
int n2, go[N][20];
void init() {
int nxt = 1;
for(int i = 1; i <= n2; ++ i) {
while(nxt <= n2 && w[nxt].L <= w[i].R) ++ nxt;
go[i][0] = nxt - 1;
}
for(int i = 1; (1 << i) <= n; ++ i) {
for(int s = 1; s <= n2; ++ s) {
go[s][i] = go[go[s][i - 1]][i - 1];
}
}
}
int res[N];
void getans(int x) {
int len = w[x].L + m, cur = x, ans = 1;
for(int i = log2(N); i >= 0; -- i) {
int pos = go[cur][i];
if(pos && w[pos].R < len) {
ans += 1 << i;
cur = pos;
}
}
res[w[x].id] = ans + 1;
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; ++ i) {
w[i].id = i;
cin >> w[i].L >> w[i].R;
if(w[i].R < w[i].L) {
w[i].R += m;
}
}
sort(w + 1, w + 1 + n);
n2 = n;
for(int i = 1; i <= n; ++ i) {
++ n2;
w[n2] = w[i];
w[n2].L = w[i].L + m;
w[n2].R = w[i].R + m;
}
init();
for(int i = 1; i <= n; ++ i) getans(i);
for(int i = 1; i <= n; ++ i) cout << res[i] << ' ';
return 0;
}
浙公网安备 33010602011771号