题目描述

有n个星球,它们的编号是1到n,它们坐落在同一个星系内,这个星系可以抽象为一条数轴,每个星球都是数轴上的一个点,
特别地,编号为i的星球的坐标是i。
一开始,由于科技上的原因,这n个星球的居民之间无法进行交流,因此他们也不知道彼此的存在。
现在,这些星球独立发展出了星际穿越与星际交流的工具。
对于第i个星球,他通过发射强力信号,成功地与编号在[Li,i-1]的所有星球取得了联系(编号为1的星球没有发出任何信号),
取得联系的两个星球会建立双向的传送门,对于建立了传送门的两个星球u,v,u上的居民可以花费1单位时间传送到v,
v上的居民也可以花费1单位时间传送到u,我们用dist(x,y)表示从编号为x的星球出发,通过一系列星球间的传送门,
传送到编号为y的星球最少需要花费的时间。
现在有q个星际商人,第i个商人初始所在的位置是xi,他的目的地是[Li,Ri]中的其中一个星球,保证Li<Ri<xi。
他会在这些星球中等概率挑选一个星球y(每个星球都有一样的概率被选中作为目的地),
然后通过一系列星球的传送门,花费最少的时间到达星球y。
商人想知道他花费的期望时间是多少?也就是计算∑dist(xi,y)/(Ri-Li+1),其中y<=Li<=Ri

输入

第一行一个正整数n,表示星球的个数。
第二行n-1个正整数,第i个正整数为Li+1,
表示编号在[Li+1,i]区间内所有星球已经与编号为i+1的星球取得了联系,并且可以通过花费1单位进行彼此的传输。保证Li+1≤i
第三行一个正整数q,表示询问组数。
接下来q行,每行三个数字Li,Ri,xi,表示在[Li,Ri]这个区间中等概率选择一个星球y,dist(xi,y)的期望。
保证Li<Ri<xi,n,q≤3×10^5

输出

对于每组询问,注意到答案必然是一个有理数,因此以p/q的格式输出这个有理数,要求gcd(p,q)=1
如果答案为整数m,输出m/1

样例输入

7
1 1 2 1 4 6
5
3 4 6
1 5 7
1 2 4
1 2 6
1 3 5

样例输出

3/2
13/5
3/2
2/1
1/1
 
首先发现一个性质,一个点往右最多只能走一步,因为走两步到达的点的l[i]一定大于走一步或者不走时的l[i]。
那么可以DP出mn[i]表示i点往右走一步或不往右走后能一步走到的最左边的点。
可以发现如果不考虑往右走一步的代价,每个点与前面每个点的最短路中代价相同的点是连续的一段。
这样每一回只要往右走到mn[i]就能最小化代价。
为什么不能是先走到中间某个点然后再能走到更远的点?
因为mn[i]是从后往前DP的,所以中间点会更新之前点的mn[i]。
对于每个点开一棵可持久化线段树存这个点到达每个点的最短路(也可以离线之后用线段树)。
实际上对于第i棵可持久化线段树存的是i之前每个点到达更新mn[i]的那个点的最短路。
对于点i,它到前面点的代价是mn[i]到每个点的代价+1。但这样没有考虑往右走一步的代价,因此每次查询时要把答案加上区间长。
可持久化线段树区间修改要标记永久化。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
inline char _read()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
int x=0,f=1;char ch=_read();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=_read();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=_read();}
return x*f;
}
int n,m;
int cnt;
int ans;
int len;
int x,y,z;
int l[300010];
int mn[300010];
int ls[8000010];
int rs[8000010];
int sum[8000010];
int num[8000010];
int root[300010];
int gcd(int x,int y)
{
if(y==0)
{
return x;
}
return gcd(y,x%y);
}
void change(int &rt,int l,int r,int L,int R,int v)
{
int now=++cnt;
ls[now]=ls[rt];
rs[now]=rs[rt];
sum[now]=sum[rt];
num[now]=num[rt];
rt=now;
if(L<=l&&r<=R)
{
num[rt]+=v;
return ;
}
sum[rt]+=(min(r,R)-max(l,L)+1)*v;
int mid=(l+r)>>1;
if(L<=mid)
{
change(ls[rt],l,mid,L,R,v);
}
if(R>mid)
{
change(rs[rt],mid+1,r,L,R,v);
}
}
int query(int rt,int l,int r,int L,int R)
{
if(!rt)
{
return 0;
}
int res=num[rt]*(min(r,R)-max(l,L)+1);
if(L<=l&&r<=R)
{
return res+sum[rt];
}
int mid=(l+r)>>1;
if(L<=mid)
{
res+=query(ls[rt],l,mid,L,R);
}
if(R>mid)
{
res+=query(rs[rt],mid+1,r,L,R);
}
return res;
}
int main()
{
n=read();
for(int i=2;i<=n;i++)
{
l[i]=read();
mn[i]=l[i];
}
for(int i=n-1;i>=1;i--)
{
mn[i]=min(mn[i+1],l[i]);
}
for(int i=2;i<=n;i++)
{
root[i]=root[mn[i]];
change(root[i],1,n,1,i-1,1);
}
m=read();
for(int i=1;i<=m;i++)
{
x=read();
y=read();
z=read();
ans=len=y-x+1;
if(x<l[z])
{
ans+=query(root[l[z]],1,n,x,min(y,l[z]-1));
}
int res=gcd(ans,len);
printf("%d/%d\n",ans/res,len/res);
}
}

BZOJ5371[Pkusc2018]星际穿越——可持久化线段树+DP的更多相关文章

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

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

  2. [PKUSC2018]星际穿越

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

  3. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  4. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

  5. 【BZOJ-2653】middle 可持久化线段树 + 二分

    2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1298  Solved: 734[Submit][Status][Discu ...

  6. HDU 4866 Shooting(持久化线段树)

    view code//第二道持久化线段树,照着别人的代码慢慢敲,还是有点不理解 #include <iostream> #include <cstdio> #include & ...

  7. 【BZOJ-3653】谈笑风生 DFS序 + 可持久化线段树

    3653: 谈笑风生 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 628  Solved: 245[Submit][Status][Discuss] ...

  8. 【BZOJ3673】&&【BZOJ3674】: 可持久化并查集 by zky 可持久化线段树

    没什么好说的. 可持久化线段树,叶子节点存放父亲信息,注意可以规定编号小的为父亲. Q:不是很清楚空间开多大,每次询问父亲操作后修改的节点个数是不确定的.. #include<bits/stdc ...

  9. 【BZOJ3207】花神的嘲讽计划I 可持久化线段树/莫队

    看到题目就可以想到hash 然后很自然的联想到可持久化权值线段树 WA:base取了偶数 这道题还可以用莫队做,比线段树快一些 可持久化线段树: #include<bits/stdc++.h&g ...

随机推荐

  1. oracle 把查询结果插入到表中几种方式

    转载:Oracle中把一个查询结果插入到一张表中 以下是信息留存: 一.Oracle数据库中,把一张表的查询结果直接生成并导入一张新表中. 例如:现有只有A表,查询A表,并且把结果导入B表中.使用如下 ...

  2. 3.1《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——下载文件

    首先,为了不手动创建一个长文件(这太麻烦了),我们将使用强大的curl(有时也写作"cURL")工具从网上下载一个文件,这个命令可以让命令行与URL交互.尽管这不是Unix核心命令 ...

  3. 获取2个集合List<T>的共同元素

    获取2个集合List<T>的共同元素,循环2个集合,然后比对. class Bj { public void GetIntersect() { , , , , , , }; , , , , ...

  4. 对int array进行排序

    今天再学习一些C#的基础知识,如对 Int Array进行排序: 你可以在控制台应用程序中,创建一个类别,它属性和2个构造函数: class Af { private int[] myVar; pub ...

  5. 学习angularjs的内置API函数

    angularjs的内置API函数有很多,如isString()判断给定的对象是否为字符串,如果是返回 true,反之返回false:isNumber()判断给定的对象是否为数字,如果是返回 true ...

  6. mybatis 缓存的使用, 看这篇就够了

    目录 1 一级缓存 1.1 同一个 SqlSession 1.2 不同的 SqlSession 1.3 刷新缓存 1.4 总结 2 二级缓存 2.1 配置二级缓存 2.2 使用二级缓存 2.3 配置详 ...

  7. [UWP 自定义控件]了解模板化控件(5):VisualState

    1. 功能需求 使用TemplatePart实现上篇文章的两个需求(Header为空时隐藏HeaderContentPresenter,鼠标没有放在控件上时HeaderContentPresent半透 ...

  8. Vue2.0 搭配 axios

    1.安装axios $ npm install axios 2.Demo (1)Get // 为给定 ID 的 user 创建请求 axios.get('/user?ID=12345') .then( ...

  9. Swarm基于多主机容器网络 - overlay networks 梳理

    前面介绍了Docker管理工具-Swarm部署记录,下面重点说下Swarm基于多主机容器通信的覆盖网络 在Docker版本1.12之后swarm模式原生支持覆盖网络(overlay networks) ...

  10. Docker容器学习梳理 - 基础环境安装

    以下是centos系统安装docker的操作记录 1)第一种方法:采用系统自带的docker安装,但是这一般都不是最新版的docker安装epel源[root@docker-server ~]# wg ...