ICPC NEAU Programming Contest 2020-D.旅游 (倍增)

https://www.jisuanke.com/contest/9342/challenges

题目描述

皮皮准备去旅游,共有n个景点可以选择,景点编号为1~n,每个景点都有一个“美观值”ai​。共有m次查询,对于第i次查询,皮皮将从xi号景点开始游览,之后他会选择沿着编号递增的顺序选择游览其他景点,但是如果这个景点的美观值不大于他刚刚游览过的景点,他就会跳过这个景点。也就是说,皮皮在游览一个美观值为u的景点v后,他将游览的下一个景点是编号大于v、美观值大于u的,编号最小的景点。皮皮将一共访问yi​个景点,请你输出他最后一个访问的景点编号,如果他不能访问yi​个景点,输出-1。
(1 <= n,m <= 1e5)

Solution

O(nlogn)
倍增思想
令mov[i][j]为从i格子开始第2^j个比i大的位置。
处理mov[i][0]时也可用单调栈优化。

转移方程 : mov[j][i] = mov[mov[j][i - 1]][i - 1]

处理完mov数组后倍增跳格子即可。

代码

#include 
using namespace std;
const int SZ = 1e5 + 10;
int mov[SZ][17],a[SZ];
int n,m;

int main()
{
	int T;
	scanf("%d",&T);
	while(T --)
	{
		memset(mov,0,sizeof(mov));
		scanf("%d%d",&n,&m);
		for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
		for(int i = n - 1;i >= 1;i --)
		{
			int now = i + 1;
			while(now != 0 && a[now] <= a[i]) now = mov[now][0];
			mov[i][0] = now;
		}
		for(int i = 1;i < 17;i ++)
			for(int j = 1;j <= n;j ++)
				mov[j][i] = mov[mov[j][i - 1]][i - 1];
		int x,y;
		while(m --)
		{
			scanf("%d%d",&x,&y);
			int now = x;
			y --;
			for(int i = 16;i >= 0;i --)
			{
				if(y & (1 << i))
					now = mov[now][i];
 			}
 			if(now != 0) printf("%d\n",now);
 			else printf("-1\n");
		}
	}	
	return 0;
}

2020.6.9

你可能感兴趣的:(倍增)