LOJ6435 & 洛谷5465 「PKUSC2018」星际穿越 倍增

题目链接:
loj6435
洛谷5465

蒟蒻zyd:这不是大水题吗?看我写个 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)的诡异ST表卡卡常数跑过去
题目:输出区间距离和
蒟蒻zyd:(笑容逐渐消失)

没想到一道倍增题能这么巧(毒)妙(瘤)……

一些奇奇怪怪的性质

这里是需要用到的性质……
为了方便,这里把“花费1单位时间进行传送”称为“走了1步”qwq
Ps.一些类似的情况就不画图了……我不会说其实是我懒QWQ

性质1

假设起始点是 s s s,如果当前走了 t t t步,能到达的最左端的点是 x x x,那么一定能在 t t t步内从 s s s到达 [ x , s − 1 ] [x,s-1] [x,s1]内的任意一点。

证明:如果某个点 p p p x ≤ p < s x\le p <s xp<s)不能到达,因为某个点向左连接的点是连续的一段,所以 s s s能到的点中的 l l l的最小值一定 > p >p >p(否则就珂以到 p p p了qwq),所以无法从 s s s能到的点中的任意一点走到 p p p左边,就矛盾了qwq
在这里插入图片描述
为什么能在 t t t步内到达呢?类似地,比如要 t + 1 t+1 t+1步才能到 p p p,那么也不能在 t t t步内到达 p p p左边(不然从 t t t步内走到 p p p左边的点走到 p p p即可qwq),矛盾qwq
所以得证。

性质2

假设起点是 s s s,终点是 x x x,那么 s s s x x x的最短路只能是这两种之一:
1.一直向左走
2.一开始先从 s s s向右走一步,再一直向左走。
换言之,如果要向右走,只能一开始向右一步,其他时候就只能向左走了。
先证明不存在从 s s s向右走两步的情况:
s s s走两次到 x x x,走一次到 y y y。若存在 l [ x ] < l [ y ] l[x]<l[y] l[x]<l[y],即向右走两步比向右走一步更优的情况:
(如图所示,蓝边是 x x x l [ x ] l[x] l[x]连的边)
在这里插入图片描述
由于一个点向左连的边的编号是连续的一段,所以 s s s一定有一条边连向 x x x,因此 s s s能一步就到 x x x,因此更优。
(如图所示, s s s能通过红边一步到达 x x x
在这里插入图片描述
若不存在 l [ x ] < l [ y ] l[x]<l[y] l[x]<l[y]的情况,那没必要走两步到 x x x了qwq,直接到 y y y然后向左走就珂以了qwq

再证明不能中途向右走的情况:
设起点 s s s向右走一步能到达的最右边的点是 r ( x ) r(x) r(x),现在走到了 x x x,如果要向右走,那么到达的点也一定在 [ x + 1 , r ( s ) ] [x+1,r(s)] [x+1,r(s)]范围内。
如果走到的点 > r ( x ) >r(x) >r(x),假设这个点为 y y y,那么 l [ y ] l[y] l[y]一定比 s s s小,所以 s s s珂以向右走一步到达 y y y,但 y > r ( x ) y>r(x) y>r(x),矛盾,所以 x x x向右走能到达的点在 [ x + 1 , r ( s ) ] [x+1,r(s)] [x+1,r(s)]范围内qwq
根据性质1,向右走一步不会让答案更优,所以就不用往右走了qwq
(其实性质1只证明了 [ x , s ] [x,s] [x,s]范围内不会使答案更优,但是脑补一下也珂以明白在 [ s + 1 , r ( s ) ] [s+1,r(s)] [s+1,r(s)]范围内也成立qwq)

综上,如果要向右走,那只能一开始向右走一步。

Ps. 有一个很显然的性质我感觉不用证明……就不把它列到上面正经证明的性质了awa
即:如果前 t t t步能到达的范围是 [ L , R ] [L,R] [L,R],那么第 t + 1 t+1 t+1不能到达的范围是 m i n { l [ i ] } , L < = i < = R min\{l[i]\},L<=i<=R min{l[i]},L<=i<=R

题目解析

倍增:
f [ i ] [ j ] f[i][j] f[i][j]表示从 i i i开始,先向右一次,再向左 2 j 2^j 2j次所能到达的最左端的点。
那么 f [ i ] [ j ] = f [ f [ i ] [ j − 1 ] ] [ j − 1 ] f[i][j]=f[f[i][j-1]][j-1] f[i][j]=f[f[i][j1]][j1]
因为由性质2,中途向右走不会使答案更优,所以从 f [ i ] [ j − 1 ] f[i][j-1] f[i][j1]向左 2 j − 1 2^{j-1} 2j1步即为 f [ i ] [ j ] f[i][j] f[i][j]
显然向左走 x + 1 x+1 x+1步会比向左 x x x步走得远,所以倍增数组是单调的。
查询就搞一个 s u m [ i ] [ j ] sum[i][j] sum[i][j],表示 i i i [ f [ i ] [ j ] , i ] [f[i][j],i] [f[i][j],i]的点的距离和qwq
然后大莉统计即珂(走出 2 i 2^i 2i步的贡献分两个部分统计)
具体见代码qwq

毒瘤代码

#include<stdio.h>
#include<cstring>
#include<algorithm>
#define re register int
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=(x<<1)+(x<<3)+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline void write(const int x) {
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
const int Size=300005;
const int INF=0x3f3f3f3f;
int n,l[Size],LOG[Size],f[Size][21],sum[Size][21];
int Calc(int x,int pos) {
	if(l[pos]<=x)	return pos-x;
	int ans=pos-l[pos];		//先向左跳一次 
	pos=l[pos];
	int cnt=1;
	//跳到再跳一次就<x的位置 
	for(re i=LOG[pos]; i>=0; i--) {
		if(f[pos][i]>x) {
			//f[pos][i]~pos到pos的距离和+pos到原点的距离*这段区间的个数 
			ans+=sum[pos][i]+(pos-f[pos][i])*cnt;
			pos=f[pos][i];
			cnt+=1<<i;
		}
	}
	return ans+(pos-x)*(cnt+1);
}
int main() {
	n=read();
	LOG[0]=-1;
	LOG[1]=0;
	for(re i=2; i<=n; i++) {
		l[i]=read();
		LOG[i]=LOG[i>>1]+1;
	}
	f[n+1][0]=INF;
	for(re i=n; i; i--) {
		f[i][0]=min(f[i+1][0],l[i]);
		sum[i][0]=i-f[i][0];		//跳一步就珂以,所以距离和为区间点数 
	}
	for(re j=1; j<=18; j++) {
		for(re i=1<<j; i<=n; i++) {
			if(f[i][j-1]) {
				f[i][j]=f[f[i][j-1]][j-1];
				sum[i][j]=sum[i][j-1]+sum[f[i][j-1]][j-1]+((f[i][j-1]-f[i][j])<<(j-1));
			}
		}
	}
	int q=read();
	while(q--) {
		int l=read();
		int r=read();
		int x=read();
		int p=Calc(l,x)-Calc(r+1,x);
		int q=r-l+1;
		int k=__gcd(p,q);
		printf("%d/%d\n",p/k,q/k);
	}
	return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值