[Luogu 5465] [LOJ 6435] [PKUSC2018]星际穿越(倍增)

题面

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

\(n \leq 10^5,l_i<r_i<x_i\)

分析

有(du)趣(liu)的倍增问题。

观察到\(l_i<r_i<x_i\),也就是说我们要求往左走的最小距离。首先差分一下,设\(sum(x,i)\)表示\(x\)到\([i,x-1]\)的最短距离和。那么答案就是\(\frac{sum(x,l)-sum(x,r+1)}{r-l+1}\)

然后我们不要直接考虑到x的最短路,而是反过来考虑走k步可以到达哪些节点。

我们从x开始走1步,可以走到哪里呢?。可以跳到的编号最小的点为\(l_x\),而最大的点应该是\(rb(x)=\max(k) (l_k \leq x)\),因为只要\(l_k \leq x\), \(x\)与\(k\)之间就有一条边。因此第1步能到达的区间是\([l_x,rb(x)]\)

第2步呢?。根据上面的分析,应该是\(\min(l_i)(i \in [l_x,rb(x)])\).但是实际上可以简化为\(\min(l_i)(i \in [l_x,n])\).因为在\([rb(x),n]\)内的点,它们的\(l\)比x还大,自然也比\([l_x,rb(x)]\)内的点的\(l\)还大,对最小值没有任何影响。

因此,设走\(k(k>1)\)步可以到达的编号最小的点为\(a\),那么走\(k+1\)步能够到达的编号最小的点为\(\min(l_i)(i\in [a,n])\).这样就可以倍增优化。

设\(f[i][j]\)表示\([i,n]\)内节点走\(2^j\)步能够到达的编号最小的点。那么显然有:

\[f[i][0]=\min(l_k),k \in[i,n]
\]

\[f[i][j]=f[f[i][j-1]][j-1]
\]

为了求答案,我们再维护一个和,\(g[i][j]\)表示\(i\)到\([f[i][j],i-1]\)内所有点的距离和。那么:

\(g[i][0]=i-f[i][0]\) (到\([f[i][0],i-1]\)中的每个点的距离都为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])
\]

这是因为:到\([f[i][j-1],i-1]\)内的节点,距离和是\(g[i][j-1]\)。而到\([f[i][j],f[i][j-1]]\)内的节点的距离由两部分组成,一部分是各节点到\(f[i][j-1]\)的距离\(g[f[i][j-1]][j-1]\),另一部分是从\(f[i][j-1]\)到\(i\)的距离\(2^{j-1}\).因为一共有\((f[i][j-1]-f[i][j])\)个节点,所以要乘上\((f[i][j-1]-f[i][j])\)

查询的话就倍增的跳即可,注意一些细节,还是直接上代码吧.

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

代码

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

[Luogu 5465] [LOJ 6435] [PKUSC2018]星际穿越(倍增)的更多相关文章

  1. LOJ.6435.[PKUSC2018]星际穿越(倍增)

    LOJ BZOJ 参考这儿qwq. 首先询问都是求,向左走的最短路. \(f[i][j]\)表示从\(i\)走到\(j\)最少需要多少步.表示这样只会\(O(n^2\log n)\)的= =但是感觉能 ...

  2. [PKUSC2018]星际穿越(倍增)

    题意:n个点的图,点i和[l[i],i)的所有点连双向边.每次询问(l,r,x)表示x到[l,r]的所有点的最短路径长度和. 首先这题显然可以线段树优化建图,但是需要比较好的常数才能通过45分,还需要 ...

  3. [PKUSC2018]星际穿越

    [PKUSC2018]星际穿越 题目大意: 有一排编号为\(1\sim n\)的\(n(n\le3\times10^5)\)个点,第\(i(i\ge 2)\)个点与\([l_i,i-1]\)之间所有点 ...

  4. [BZOJ4444] [Luogu 4155] [LOJ 2007] [SCOI2015]国旗计划(倍增)

    [BZOJ4444] [Luogu 4155] [LOJ 2007] [SCOI2015]国旗计划(倍增) 题面 题面较长,略 分析 首先套路的断环为链.对于从l到r的环上区间,若l<=r,我们 ...

  5. LOJ #6435. 「PKUSC2018」星际穿越(倍增)

    题面 LOJ#6435. 「PKUSC2018」星际穿越 题解 参考了 这位大佬的博客 这道题好恶心啊qwq~~ 首先一定要认真阅读题目 !! 注意 \(l_i<r_i<x_i\) 这个条 ...

  6. BZOJ5371[Pkusc2018]星际穿越——可持久化线段树+DP

    题目描述 有n个星球,它们的编号是1到n,它们坐落在同一个星系内,这个星系可以抽象为一条数轴,每个星球都是数轴上的一个点, 特别地,编号为i的星球的坐标是i. 一开始,由于科技上的原因,这n个星球的居 ...

  7. 【洛谷5465】[PKUSC2018] 星际穿越(倍增)

    点此看题面 大致题意: 给定\(l_{2\sim n}\),其中\(l_i\)表示\([l_i,i-1]\)的所有点与\(i\)之间存在一条长度为\(1\)的双向路径.每次询问给出\(l,r,x\), ...

  8. LOJ6435 PKUSC2018 星际穿越

    这个题吧当时在考场只得了45分 然后70分的性质都分析到了 不知道为啥就是写萎蛋了 哎 当时还是too young too simple 看了一下julao们的博客这个题有两种做法 一个是比较费脑子的 ...

  9. 2019.03.09 bzoj5371: [Pkusc2018]星际穿越(主席树)

    传送门 题意简述: 给一个序列,对于第iii个位置,它跟[limi,i−1][lim_i,i-1][limi​,i−1]这些位置都存在一条长度为111的无向边. 称dist(u,v)dist(u,v) ...

随机推荐

  1. PIXI兼容微信小游戏

    首先导入官方的weapp-adapter,然后导入pixi.min.js,微信小程序使用ES6的module引用模块,具体参见ES6的Module. import './libs/weapp-adap ...

  2. php使用ob缓存来实现动态页面静态化

    php7中的php.ini 默认开启 output_buffering = 4096 例子: <?phpinclude_once 'common/common.php';//数据库操作方法 $f ...

  3. end of sleepyhead

  4. 莫队算法 ( MO's algorithm )

    莫队算法是由清华大学神牛莫涛发明的一种处理区间问题的离线算法 算法核心是通过先将问询区间总长度平方分块.然后将所有的问询区间按照左端点所在的块编号排序.在同一块内的则按右端点升序 然后设置左右两个下标 ...

  5. TTTTTTTTTTT LA 4329 BIT模版

    题意: 有n个打乒乓球的人,住在一排房子内,以房子的顺序从做到由,每个人都有一个不同的乒乓球等级ai.每次比赛需要三人,两人比赛和一人裁判,裁判必须居住在两个比赛者之间,且等级必须也在两个人之间.问最 ...

  6. 微信长按识别二维码,在 vue 项目中的实现

    微信长按识别二维码是 QQ 浏览器的内置功能,该功能的基础一定要使用 img 标签引入图片,其他方式的二维码无法识别. 在 vue 中使用 QrcodeVue 插件 demo1 在 template ...

  7. chrome插件报错原因

    Chrome报错提示Unchecked runtime.lastError: The message port closed before a response was received. 出错原因: ...

  8. Java并发编程的艺术笔记(一)——volatile和syncronized关键字

    一.线程间的通信 volatile和syncronized关键字 volatile 修饰变量,告知任何对该变量的访问必须从共享内存获取,对它的改变必须同步刷新至共享内存,由此保证可见性. syncro ...

  9. intellij idea中去除@Autowired注入对象的红色波浪线提示

    idea中通过@Autowired注入的对象一直有下划线提示. 解决:改变@Autowired的检查级别即可. 快捷键:Ctrl+Alt+s,进入idea设置界面,输入inspections检索

  10. java第二周小结

    这是接触Java的第一周,了解这个语言的一些基础知识,下面是对这段时间重要知识点的汇总 一.Java是一种面向对象的语言    特点为:简洁高效.可移植性.适合分布式计算.健壮防患于未然的特性.多线程 ...