[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. Python并发编程之IO模型

    目录 IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) IO多路复用 异步IO IO模型比较分析 selectors模块 一.IO模型介绍 Stevens ...

  2. vue-cli3.0 gui(一)

    vue-cli3.0 gui 安装: npm i core-js -g:用于JavaScript的模块化标准库. npm i -g @vue/cli:vue的脚手架工具 运行: vue ui:运行vu ...

  3. Numpy系列(十三)- 文件IO

    NumPy提供了多种存取数组内容的文件操作函数.保存数组数据的文件可以是二进制格式或者文本格式.二进制格式的文件又分为NumPy专用的格式化二进制类型和无格式类型. 一,tofile()和fromfi ...

  4. java集合分割

    java集合分割成等份的小集合: private <T> List<List<T>> getSubList(List list,int len) { if(list ...

  5. Git以及TortoiseGit的下载安装使用

    Git以及TortoiseGit的下载安装使用 下载git 下载地址:https://git-scm.com/然后进行一系列的安装,傻瓜式的操作即可 TortoiseGit Tortoise 英[ˈt ...

  6. 第二十节: 深入理解并发机制以及解决方案(锁机制、EF自有机制、队列模式等)

    一. 理解并发机制 1. 什么是并发,并发与多线程有什么关系? ①. 先从广义上来说,或者从实际场景上来说. 高并发通常是海量用户同时访问(比如:12306买票.淘宝的双十一抢购),如果把一个用户看做 ...

  7. 微信获取企业token流程

    1.获取服务商Accesstoken(每10分钟企业微信会推送一次,两个小时后过期) 2.根据suitid.accesstoken.第三方企业corpid.第三方企业permanentcode,得到第 ...

  8. Collections of Zujin Zhang's Published works

    I am not good, but I shall do my best to be better. Any questions, please feel free to contact zhang ...

  9. SSRF漏洞挖掘经验

    SSRF概述 SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞.一般情况下,SSRF攻击的目标是从外网无法访问 ...

  10. Set集合判断对象重复的方法

    Set<User> userSet = new HashSet<>(); User user1= new User("aa","11") ...