概述
Description
n个点的图,点i和[l[i],i)的所有点连双向边。每次询问(l,r,x)表示x到[l,r]的所有点的最短路径长度和。
Sample Input
7
1 1 2 1 4 6
5
3 4 6
1 5 7
1 2 4
1 2 6
1 3 5
Sample Output
3/2
13/5
3/2
2/1
1/1
这篇blog写的不错,可以了解一下。
然后在BZOJ会T,就把LL删了,竟然过了。。。
#include <cstdio>
#include <cstring>
using namespace std;
int _min(int x, int y) {return x < y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
typedef long long LL;
int f[20][310000], L[310000];
int s[20][310000];
int gcd(int a, int b) {
if(b == 0) return a;
return gcd(b, a % b);
}
inline int calc(int l, int r) {
if(L[r] <= l) return r - l;
int ans = r - L[r], tot = 1; r = L[r];
for(int j = 18; j >= 0; j--) {
if(f[j][r] > l) ans += s[j][r] + (r - f[j][r]) * tot, r = f[j][r], tot += 1 << j;
} ans += (r - l) * (tot + 1);
return ans;
}
int main() {
int n = read();
for(int i = 2; i <= n; i++) L[i] = read();
s[0][n] = n - L[n]; f[0][n] = L[n];
for(int i = n - 1; i >= 2; i--) f[0][i] = _min(f[0][i + 1], L[i]), s[0][i] = i - f[0][i];
for(int i = 1; i <= 18; ++i) {
for(int j = (1 << i); j <= n; ++j) {
f[i][j] = f[i - 1][f[i - 1][j]];
s[i][j] = s[i - 1][j] + s[i - 1][f[i - 1][j]] + (f[i - 1][j] - f[i][j]) * (1LL << i - 1);
}
} int m = read();
for(int i = 1; i <= m; ++i) {
int l = read(), r = read(), x = read();
int ans = calc(l, x) - calc(r + 1, x);
int uu = r - l + 1, d = gcd(ans, uu);
printf("%d/%dn", ans / d, uu / d);
}
return 0;
}
最后
以上就是悲凉犀牛为你收集整理的[PKUSC2018]星际穿越 倍增DP的全部内容,希望文章能够帮你解决[PKUSC2018]星际穿越 倍增DP所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复