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 <bits/stdc++.h>
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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章