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