[PKUSC2018]星际穿越

题目大意:

有一排编号为\(1\sim n\)的\(n(n\le3\times10^5)\)个点,第\(i(i\ge 2)\)个点与\([l_i,i-1]\)之间所有点有双向边。\(q(q\le3\times10^5)\)次询问,每次对于\(l_i,r_i,x_i\),求\(\frac{\sum_{y=l_i}^{r_i}dist(x_i,y)}{r_i-l_i+1}\)。

思路:

首先可以得到一个基本结论,从\(x_i\)出发到\(y\)的最短路中,一定存在至少一种满足路径上有且仅有第一步是向右走的,或者直接往左走。那么我们不妨对于每一个点\(x\),求出\(x\)右侧\(l_i\)最小的\(i=min[x]\),此时\(i\)的覆盖范围一定包含了\(x\)。让\(x\)向\(i\)连边就得到了一个树形结构。在树上每个结点建立主席树维护原图每个点到树上对应结点的距离。

询问时对于\(l_i,r_i,x_i\),若区间\([l_i,r_i]\)内的结点都与\(x_i\)有连边,则答案就是\(r_i-l_i+1\)。否则那些在\(x_i\)连边范围外的那些点到\(x_i\)的距离,就是主席树上到\(min[x_i]\)的距离\(+1\)。到\(min[x_i]\)的距离可以主席树上询问,剩下的\(+1\)一并计算到\(r_i-l_i+1\)中即可。

时间复杂度\(\mathcal O(n\log n)\)。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=3e5+1,SIZE=N*30;
int left[N],min[N],par[N];
class SegmentTree {
private:
struct Node {
int left,right,tag,sum;
};
Node node[SIZE];
int sz,new_node(const int &p) {
node[++sz]=node[p];
return sz;
}
public:
int root[N];
void modify(int &p,const int &b,const int &e,const int &l,const int &r) {
p=new_node(p);
if(b==l&&e==r) {
node[p].tag++;
return;
}
node[p].sum+=r-l+1;
const int mid=(b+e)>>1;
if(l<=mid) modify(node[p].left,b,mid,l,std::min(mid,r));
if(r>mid) modify(node[p].right,mid+1,e,std::max(mid+1,l),r);
}
int query(const int &p,const int &b,const int &e,const int &l,const int &r) {
if(!p) return 0;
int ans=node[p].tag*(r-l+1);
if(b==l&&e==r) return ans+node[p].sum;
const int mid=(b+e)>>1;
if(l<=mid) ans+=query(node[p].left,b,mid,l,std::min(mid,r));
if(r>mid) ans+=query(node[p].right,mid+1,e,std::max(mid+1,l),r);
return ans;
}
};
SegmentTree t;
int gcd(const int &a,const int &b) {
return b?gcd(b,a%b):a;
}
int main() {
const int n=getint();
for(register int i=2;i<=n;i++) left[i]=getint();
min[par[n]=n]=left[n];
for(register int i=n-1;i;i--) {
min[i]=std::min(min[i+1],left[i]);
par[i]=par[min[i]]?:i;
}
for(register int i=2;i<=n;i++) {
if(par[i]==i) t.modify(t.root[i]=t.root[min[i]],1,n,1,i-1);
}
for(register int i=2;i<=n;i++) {
t.root[i]=t.root[i]?:t.root[par[i]];
}
for(register int q=getint();q;q--) {
const int l=getint(),r=getint(),x=getint();
int ans=r-l+1;
if(l<left[x]) ans+=t.query(t.root[left[x]],1,n,l,std::min(r,left[x]-1));
const int d=gcd(ans,r-l+1);
printf("%d/%d\n",ans/d,(r-l+1)/d);
}
return 0;
}

[PKUSC2018]星际穿越的更多相关文章

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

    [Luogu 5465] [LOJ 6435] [PKUSC2018]星际穿越(倍增) 题面 n个点的图,点i和[l[i],i)的所有点连双向边.每次询问(l,r,x)表示x到[l,r]的所有点的最短 ...

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

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

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

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

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

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

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

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

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

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

  7. LOJ6435 PKUSC2018 星际穿越

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

  8. 题解 洛谷 P5465 【[PKUSC2018]星际穿越】

    首先考虑题目的性质,发现点向区间连的边为双向边,所以也就可以从一个点向右跳到区间包含该点的点,如图所示: 但事实上向后跳其实是不优的,可以有更好的方法来节省花费: 因此我们发现一个点跳到其前一个区间的 ...

  9. 「PKUSC2018」星际穿越 (70分做法)

    5371: [Pkusc2018]星际穿越 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 27  Solved: 11[Submit][Status] ...

随机推荐

  1. luoguP4841 城市规划

    题意: 求n个点的无相连通图的个数.有编号 思路一: 黏博客 至于为什么除以k!:(没有博客中说的那么简单) 实际上, 对于一个n的用k个自然数的拆分,每一个拆分的贡献是: $\frac{n!*\Pi ...

  2. 洛谷P2120 [ZJOI2007]仓库建设 斜率优化DP

    做的第一道斜率优化\(DP\)QwQ 原题链接1/原题链接2 首先考虑\(O(n^2)\)的做法:设\(f[i]\)表示在\(i\)处建仓库的最小费用,则有转移方程: \(f[i]=min\{f[j] ...

  3. 继续沿用旧的网络访问模式Apache HTTP 客户端,防止Android9闪退

    注意位置,在application 节点里面.

  4. 任意模数NTT学习笔记

    这两天有点颓,所以东西学的也很慢...这个一眼就能推出来的活生生卡了我两天.. 说几个细节: 柿子: \[f*g = (\frac{f}{M} +f\%m)*(\frac{g}{M} +g\%m) \ ...

  5. Git 分支 (二)合并

    分支的新建与合并 让我们来看一个简单的分支新建与分支合并的例子,实际工作中你可能会用到类似的工作流. 你将经历如下步骤:1. 开发某个网站.2. 为实现某个新的需求,创建一个分支.3. 在这个分支上开 ...

  6. 利用 /proc/sys/kernel/core_pattern隐藏系统后门

    ref:https://xz.aliyun.com/t/1098/ 这里所说的core_pattern 指的是:/proc/sys/kernel/core_pattern. 我们知道在Linux系统中 ...

  7. [再寄小读者之数学篇](2014-06-22 发散级数 [中国科学技术大学2012年高等数学B考研试题])

    设 $a_n>0$, $S_n=a_1+a_2+\cdots+a_n$, 级数 $\dps{\vsm{n}a_n}$ 发散, 证明: $\dps{\vsm{n}\cfrac{a_n}{S_n}} ...

  8. MD5 两次加密

    1.添加依赖 <dependency> <groupId>commons-codec</groupId> <artifactId>commons-cod ...

  9. Windows server 2012配置WebDeploy发布网站

    以前都是使用win2008r2服务器,最近更新了操作系统到WINDOWS 2012,发现以前的做法已经不适用了. win2008r2配置WebDeploy: https://www.cnblogs.c ...

  10. 更改Ubuntu默认python版本的方法

    当你安装 Debian Linux 时,安装过程有可能同时为你提供多个可用的 Python 版本,因此系统中会存在多个 Python 的可执行二进制文件.一般Ubuntu默认的Python版本都为2. ...