题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2002
思路:不使用动态树的做法:
将这个序列划分为 sqrt(n) 块,对于序列中每个元素维护一个ed[i],代表从i跳出当前所在的块后重点位置,times[i]表示从i跳出这个块所需要的步数
初始化过程中从后往前操作
对于查询操作,最多只需要sqrt(n)次加法即可跳出整个序列
对于修改操作, 只需要修改这个块内i和i以前位置的ed[i]和times[i]
初始化操作O(n)
查血和修改操作都是O(sqrt(n))
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <cstdio>
#include <time.h>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <math.h>
//#include <bits/stdc++.h>
#define ll long long
#define int64 long long
#define mem(x,y) memset(x,y,sizeof(x))
#define ull unsigned long long
#define pb push_back
#define INF 0x3f3f3f3f
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
#define pi 3.141592653589793238462
#define stdio std::ios::sync_with_stdio(false)
using namespace std;
inline bool nextDouble(double &num) {
char in;
double Dec = 0.1;
bool IsN = false, IsD = false;
in = getchar();
if (in == EOF) return false;
while (in != '-' && in != '.' && (in < '0' || in > '9'))
in = getchar();
if (in == '-') {
IsN = true;
num = 0;
} else if (in == '.') {
IsD = true;
num = 0;
} else num = in - '0';
if (!IsD) {
while (in = getchar(), in >= '0' && in <= '9') {
num *= 10;
num += in - '0';
}
}
if (in != '.') {
if (IsN) num = -num;
return true;
} else {
while (in = getchar(), in >= '0' && in <= '9') {
num += Dec * (in - '0');
Dec *= 0.1;
}
}
if (IsN) num = -num;
return true;
}
inline bool nextInt(int &num) {
char in;
bool IsN = false;
in = getchar();
if (in == EOF) return false;
while (in != '-' && (in < '0' || in > '9')) in = getchar();
if (in == '-') {
IsN = true;
num = 0;
} else num = in - '0';
while (in = getchar(), in >= '0' && in <= '9') {
num *= 10, num += in - '0';
}
if (IsN) num = -num;
return true;
}
inline bool nextLong(ll &num) {
char in;
bool IsN = false;
in = getchar();
if (in == EOF) return false;
while (in != '-' && (in < '0' || in > '9')) in = getchar();
if (in == '-') {
IsN = true;
num = 0;
} else num = in - '0';
while (in = getchar(), in >= '0' && in <= '9') {
num *= 10, num += in - '0';
}
if (IsN) num = -num;
return true;
}
const int maxn = 2e5 + 200;
const int maxm = 1e3 + 5;
const int mod = 1e9 + 7;
const int seed = 10007;
const double eps = 1e-6;
int n, m;
int a[maxn];
int ed[maxn], times[maxn];
int main() {
//stdio;
nextInt(n);
for (int i = 0; i < n; i++) {
nextInt(a[i]);
}
int block = static_cast<int>(sqrt(n) + 1e-7);
for (int i = n - 1; i >= 0; i--) {
int tmp = i + a[i];
if (tmp >= n) {
ed[i] = -1;
times[i] = 1;
} else if (tmp >= (i / block + 1)*block) {
ed[i] = tmp;
times[i] = 1;
} else {
ed[i] = ed[tmp];
times[i] = times[tmp] + 1;
}
}
nextInt(m);
while (m--) {
int x, y, z;
nextInt(x);
if (x == 1) {
nextInt(y);
int ans = 0;
for (int i = y; i >= 0; i = ed[i]) ans += times[i];
printf("%d\n",ans);
} else {
nextInt(y);
nextInt(z);
a[y] = z;
for (int i = y; i >= y / block * block; i--) {
int tmp = i + a[i];
if (tmp > n - 1) ed[i] = -1, times[i] = 1;
else if (tmp >= (i / block + 1)*block) ed[i] = tmp, times[i] = 1;
else ed[i] = ed[tmp], times[i] = times[tmp] + 1;
}
}
}
return 0;
}
顺便一提被BZOJ卡cin卡成智障……不知道为什么只要用cin就是RE……
本文介绍了一种解决区间跳跃问题的有效算法,通过将序列划分成多个块并维护每个块的状态信息来实现快速查询和更新操作。此方法避免了使用复杂的数据结构如动态树,采用简单的数组和数学计算达到O(√n)的时间复杂度。

209

被折叠的 条评论
为什么被折叠?



