Solution - Holes
Link。
暴力做是 的。怎么优化呢?I've no slightest idea😢
结果用到了一个特别神的东西,罗阿姨认为 useless 的东西——分块。想到这个就豁然开朗了!
假设块长为 , 表示从 开始跳在块内的步数, 表示从 开始跳在块内的最后到达的点。我们分成若干段,如果对于 ,跳完之后还在同一块内就简单转移一下,否则说明跳到其它块里去了,相当于当前块里的结束点, 即本身,那么 。
询问的话,每次先算当前块内的,然后跳到 跳的下一个点,这样就会计算下一个块。如果 再跳一步就 了,直接跳出循环,否则说明还会计算下一个块,直接跳就可以了。。
更新只更新一段。。
总的就是 。由于神秘原因块长设为 才可以过。
原因是询问比较多,这样平衡一下。
namespace liuzimingc {
const int N = 2e5 + 5; // i + pos[i] 可能会 RE,开两倍,也可以单独判一下是否 > n
#define endl '\n'
int n, m, p[N], f[N], to[N], block, pos[N], l[N], r[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
cin >> n >> m;
block = (int)2 * sqrt(n);
for (int i = 1; i <= n; i++) {
cin >> p[i];
pos[i] = (i - 1) / block + 1;
}
for (int i = 1; i <= n; i++)
if (!l[pos[i]]) l[pos[i]] = i;
for (int i = n; i; i--)
if (!r[pos[i]]) r[pos[i]] = i;
for (int i = n; i; i--)
if (pos[i + p[i]] == pos[i]) f[i] = f[i + p[i]] + 1, to[i] = to[i + p[i]]; // 简单转移一下
else f[i] = 1, to[i] = i;
while (m--) {
int op, a;
cin >> op >> a;
if (op) {
int sum = 0;
while (true) {
sum += f[a];
a = to[a];
if (a + p[a] > n) break;
a += p[a];
}
cout << a << " " << sum << endl;
}
else {
cin >> p[a];
for (int i = r[pos[a]]; i >= l[pos[a]]; i--)
if (pos[i + p[i]] == pos[i]) f[i] = f[i + p[i]] + 1, to[i] = to[i + p[i]];
else f[i] = 1, to[i] = i;
}
}
return 0;
}
} // namespace liuzimingc
Posted by liuzimingc
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)