zoukankan      html  css  js  c++  java
  • [PKUSC2018]星际穿越(倍增)

    题意:n个点的图,点i和[l[i],i)的所有点连双向边。每次询问(l,r,x)表示x到[l,r]的所有点的最短路径长度和。

    首先这题显然可以线段树优化建图,但是需要比较好的常数才能通过45分,还需要发掘性质。

    先不考虑往右走的情况,对于一个点x,每个点i与x的最短距离一定形成一个个连续区间,即:设f[i][j]表示i走j步能到的最左的点,则$f[i][j+1]=minlimits_{k=f[i][j]}^{i-1}l[k]$。所以只要往前扫一遍就能求出f[i]数组。

    接着考虑往右走的情况,可以证明,一个点最多只需要往右走一次,所以只需要往后扫一遍就能求出新的f[i]数组。这样我们记录一个前缀和就可以在$O(n^2)$复杂度内解决问题。

    可以发现f[i][j]这个数组显然是可以倍增优化的,直接套上RMQ类似的模板即可。

    这里有一个简化代码的方法,就是f[i][j]改为表示[i..n]的所有点走$2^j$步之后能到达的最靠前的点,这样就可以直接倍增转移了。但是这样就要判断i最后是否需要先往右走一步,这里又有一个小技巧:先强制往左走一步,剩下的直接处理即可。

    总码长不到1k。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 typedef long long ll;
     5 using namespace std;
     6 
     7 const int N=300010;
     8 int n,Q,l,r,x,L[N],to[20][N];
     9 ll sm[20][N];
    10 
    11 int gcd(int a,int b){ return b ? gcd(b,a%b) : a; }
    12 
    13 ll calc(int l,int r){
    14     if (L[r]<=l) return r-l;
    15     ll ans=r-L[r]; r=L[r]; int tot=1;
    16     for (int i=19; ~i; i--)
    17         if (to[i][r]>l) ans+=sm[i][r]+tot*(r-to[i][r]),r=to[i][r],tot+=1<<i;
    18     return ans+(r-l)*(tot+1);
    19 }
    20 
    21 int main(){
    22     freopen("pkua.in","r",stdin);
    23     freopen("pkua.out","w",stdout);
    24     scanf("%d",&n); L[1]=1;
    25     rep(i,2,n) scanf("%d",&L[i]);
    26     to[0][n]=L[n]; sm[0][n]=n-L[n];
    27     for (int i=n-1; i; i--) to[0][i]=min(to[0][i+1],L[i]),sm[0][i]=i-to[0][i];
    28     rep(i,1,19) rep(j,1,n) if (to[i-1][j]){
    29         to[i][j]=to[i-1][to[i-1][j]];
    30         sm[i][j]=sm[i-1][j]+sm[i-1][to[i-1][j]]+(to[i-1][j]-to[i][j])*(1ll<<(i-1));
    31     }
    32     for (scanf("%d",&Q); Q--; ){
    33         scanf("%d%d%d",&l,&r,&x);
    34         ll a=calc(l,x)-calc(r+1,x),b=r-l+1; int d=gcd(a%b,b);
    35         printf("%lld/%lld
    ",a/d,b/d);
    36     }
    37     return 0;
    38 }
  • 相关阅读:
    HDU 1754线段树基本操作,建树,更新,查询
    用第三方下载工具下载官方XCode独立安装包的方法
    解决Windows平台通过cURL上传APP到蒲公英pgyer平台时无法使用中文升级描述的问题
    Cygwin 版本的 Curl 安装,提取,使用笔记
    Android Gradle 引用本地 AAR 的几种方式
    VM虚拟机快照还原效果实现方式
    插入中文错误ERROR 1406 (22001): Data too long for column 'name' at row 1
    mysql初始化默认为空的密码修改
    性能测试学习计划(转)
    context-param和init-param区别
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9166459.html
Copyright © 2011-2022 走看看