[Luogu 5465] [LOJ 6435] [PKUSC2018] Interstellar (multiplication)
Face questions
FIG n points, point i and [L [i], i) of all points connected bidirectional edge. Always ask (l, r, x) represents the shortest path length to all points x [l, r], and / (r-l + 1).
\(n \leq 10^5,l_i<r_i<x_i\)
analysis
There are (du) Fun (liu) multiplication problem.
Observed \ (L_i <r_i <x_i \) , which means we require a minimum distance left to go. First look at the difference, provided \ (sum (x, i) \) represents \ (X \) to \ ([i, x-1 ] \) of the shortest distance. The answer is \ (\ frac {sum (x , l) -sum (x, r + 1)} {r-l + 1} \)
Then we do not directly take into account the shortest x, but conversely consider what steps away k nodes can be reached.
We started to go one step from x, where can it go? . Can jump to the minimum point number \ (L_x \) , and the largest point should be \ (RB (X) = \ max (K) (L_K \ Leq X) \) , as long as \ (l_k \ leq x \) , \ (X \) and \ (K \) there is an edge between. Thus Interval Step 1 is to reach the \ ([l_x, rb (x )] \)
Step 2 it? . According to the above analysis, it should be \ (\ min (l_i) ( i \ in [l_x, RB (X)]) \) ., But may actually be reduced to \ (\ min (l_i) ( i \ in [l_x, n-]) \) . because \] \) n ([rb (x), the point in their \ (L \) larger than x, Nature than \ ([l_x, rb (x )] \ ) points in the \ (l \) is bigger, has no effect on the minimum.
Thus, set down \ (k (k> 1) \) minimum point number steps can reach as \ (A \) , then go \ (k + 1 \) minimum point number steps to reach as \ (\ min (L_i) (I \ in [A, n-]) \) . This multiplication can be optimized.
Set \ (f [i] [j ] \) represents \ ([i, n] \ ) within a node trace \ (2 ^ j \) step to reach the minimum number of points. Then clearly there:
\[f[i][0]=\min(l_k),k \in[i,n]\]
\[f[i][j]=f[f[i][j-1]][j-1]\]
To find the answer, we have to maintain a and, \ (G [I] [J] \) represents \ (I \) to \ ([f [i] [ j], i-1] \) from all points with. Then:
\ (G [I] [0] = IF [I] [0] \) (the \ ([f [i] [ 0], i-1] \) distance of each point are 1)
\[g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1]+2^{j-1}(f[i][j-1]-f[i][j])\]
This is because: the \ ([f [i] [ j-1], i-1] \) nodes, the distance is \ (G [I] [J-. 1] \) . By \ ([f [i] [ j], f [i] [j-1]] \) from the nodes within a two-part, part of each node to \ (f [i] [j -1 ] \) distance \ (G [F [I] [J-. 1]] [J-. 1] \) , the other part from \ (f [i] [j -1] \) to \ (I \) distance \ (J-2. 1 ^ {} \) . since a total of \ ((f [i] [ j-1] -f [i] [j]) \) nodes, so multiplied by \ (( f [i] [j-1 ] -f [i] [j]) \)
Then the query would double the jump can pay attention to some details, or directly on the code.
int calc(int x,int l){ //sum(x,l),[l,x-1]内答案
if(a[x]<=l) return x-l;//只需走一次的情况,特判
//第一次走的答案
int ans=x-a[x];//距离和
int cnt=1;//走的次数
x=a[x];
for(int i=log2n;i>=0;i--){
if(f[x][i]>=l){
ans+=g[x][i]+cnt*(x-f[x][i]);//,g[x][i]为当前这段的距离和,但是之前每个节点还跳了cnt步到x,因此要加上cnt*[f[x][i],x-1]
cnt+=(1<<i);
x=f[x][i];
}
}
if(x>l) ans+=x-l+cnt*(x-l);//如果最后一步没跳满,加上f[x][i]
return ans;
}
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 300000
#define maxlogn 25
using namespace std;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int n,q;
int log2n;
int a[maxn+5];
int f[maxn+5][maxlogn+5];
int g[maxn+5][maxlogn+5];
int calc(int x,int l){ //[l,x-1]内答案
if(a[x]<=l) return x-l;
//特判第一次跳
int ans=x-a[x];
int cnt=1;
x=a[x];
for(int i=log2n;i>=0;i--){
if(f[x][i]>=l){
ans+=g[x][i]+cnt*(x-f[x][i]);//[f[x][i],x-1]跳到x还需cnt步
cnt+=(1<<i);
x=f[x][i];
}
}
if(x>l) ans+=x-l+cnt*(x-l);//如果最后一步没跳满,加上f[x][i]
return ans;
}
int main(){
int l,r,x;
scanf("%d",&n);
log2n=log2(n)+1;
a[1]=1;
for(int i=2;i<=n;i++) scanf("%d",&a[i]);
f[n][0]=a[n];
for(int i=n-1;i>=1;i--){
f[i][0]=min(f[i+1][0],a[i]);
g[i][0]=i-f[i][0];
}
for(int j=1;j<=log2n;j++){
for(int i=1;i<=n;i++){
if(f[i][j-1]){
f[i][j]=f[f[i][j-1]][j-1];
g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1]+((f[i][j-1]-f[i][j])<<(j-1));
//[f[i][j],f[i][j-1]-1]内的点跳到j还需2^{j-1}步
}
}
}
scanf("%d",&q);
while(q--){
scanf("%d %d %d",&l,&r,&x);
int up=calc(x,l)-calc(x,r+1);
int down=r-l+1;
int g=gcd(up,down);
up/=g;
down/=g;
printf("%d/%d\n",up,down);
}
}