Luogu P5465 [PKUSC2018] 星际穿越

观察可以发现一个结论,可以视作每个点 i 可以一步到达 lin 的每一个点。

发现对于 a<b<xdist(a,x)dist(b,x)

第一步是相当特殊的,因为第一步的起点是一个点,而之后的每一步都可以视作从这一段中的任意点出发

于是我们特殊处理第一步,然后将第二步当作第一步

那么,新的第一步是从 lxn 的任意一个点出发

第二步是从 minklx{lk}n 的任意一个点出发

于是可以考虑倍增

fi,j 表示从 jn 的任意一个点出发,走 2i 步能到达的最靠左的点

那么,走 2i 步能到达 fi,jn 的每一个点

于是我们可以得到转移

fi,j=fi1,fi1,j

初始条件为

f0,j=minkj{lk}

那么我们用 gi,j 表示从 jn 的任意一个点出发,到 fi,jj1 的最短步数之和

gi,j=gi1,j+2i1(fi1,jfi,j)+gi1,fi1,j

初始条件为

g0,j=jf0,j

计算时倍增即可,注意加上之前被忽略的第一步。

#include <bits/stdc++.h> using namespace std; int n, l[300005]; int q, a, b, x; int f[25][300005]; long long g[25][300005]; long long query(int a, int x) { int now = l[x]; if (now <= a) return x - a; long long ans = 0; for (int i = log2(n); i >= 0; i--) { if (f[i][now] >= a) { ans += g[i][now]; now = f[i][now]; ans += 1ll * (now - a) * (1ll << i); } } ans += now - a; return ans + (x - a); } int main() { scanf("%d", &n); l[1] = 1; for (int i = 2; i <= n; i++) { scanf("%d", l + i); } for (int i = n, minx = 0x7fffffff; i >= 1; i--) { minx = min(minx, l[i]); f[0][i] = minx; g[0][i] = i - f[0][i]; } for (int i = 1; i <= log2(n); i++) { for (int j = 1; j <= n; j++) { f[i][j] = f[i - 1][f[i - 1][j]]; g[i][j] = g[i - 1][j] + g[i - 1][f[i - 1][j]] + (1ll << (i - 1)) * (f[i - 1][j] - f[i][j]); } } scanf("%d", &q); while (q--) { scanf("%d%d%d", &a, &b, &x); long long ans = query(a, x) - query(b + 1, x), len = b - a + 1; long long gcd = __gcd(ans, len); printf("%lld/%lld\n", ans / gcd, len / gcd); } return 0; }

__EOF__

本文作者0922-Blog
本文链接https://www.cnblogs.com/0922-Blog/p/luogu_P5465.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   wiki0922  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示