[Luogu 5465] [LOJ 6435] [PKUSC2018] Interstellar (multiplication)

[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);
    }
}

Guess you like

Origin www.cnblogs.com/birchtree/p/11521717.html