太空旅行:倍增+位运算
作者:互联网
http://172.20.8.83/showsource.php?id=2968
题目描述
乐乐准备去太空旅行,共有 n 个星球可以选择,星球编号为 1 ~ n,每个星球都有一个“游览值”ai。
共有 m 次查询,对于第 i 次查询,乐乐将从 xi 号星球开始游览,之后他会选择沿着编号递增的顺序选择游览其他星球,
但是如果这个星球的浏览值不大于他刚刚游览过的星球,他就会跳过这个星球。
也就是说,乐乐在游览一个浏览值为 u 的星球 v 后,他将游览的下一个星球是编号大于 v、浏览值大于 u 的,编号最小的星球。
乐乐将一共访问 yi 个星球,请你输出 他最后一个访问的星球编号,如果他不能访问 yi 个星球,输出-1输入格式
输入第一行一个整数 T,代表接下来有 T 组测试数据
接下来 T 组,每组第一行有两个整数 n, m,
第二行有 n 个整数 ai,
接下来 m 行,每行有两个整数 xi, yi
1 ≤ T ≤ 5
1 ≤ n, m ≤ 105
1 ≤ ai ≤ 109
1 ≤ xi, yi ≤ n输出格式
对于每组测试数据,输出一行,一个整数。
如果能游览 yi个星球,输出最后访问的星球编号,否则输出-1输入样例 复制
1 15 10 1 2 3 4 5 3 4 5 6 7 5 6 7 8 9 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10
输出样例 复制
1 2 3 4 5 9 10 14 15 -1
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
typedef long long ll;
int n,m, a[N],nex[N][17];//2^17>1e5,注意下面一定不能取到17 会越界
stack<int>s;
void init(){
s.push(0);//防止到栈底访问越界
s.push(1);
a[n+1]=inf;
for(int i=2;i<=n+1;i++){
while(s.top()!=0&&a[s.top()]<a[i]){
nex[s.top()][0]=i;//cur开始往后一位(2^0=1)
s.pop();
}
s.push(i);
}
//把n+1节点也放入实现:若nex[i][0]==n+1,则i为最后一个节点
}
int main(){
int t,x,y;
cin>>t;
while(t--) {
memset(nex,0,sizeof(nex));
while(!s.empty()) s.pop();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
}
init();//倍增(nex为n+1代表没有可访问的了)
for(int i=0;i<17;i++) nex[n+1][i]=n+1;//(2^0=1别忘了)。
//已知到未知,小区间到大区间。从已知的j后2^0个递推得到j后2^i个
for(int i=1;i<17;i++)
for(int j=1;j<=n;j++)
nex[j][i]=nex[nex[j][i-1]][i-1];
while(m--){
scanf("%d%d",&x,&y);//从a[x]开始,一共y个(包括x)
y--;//减去初始自己的那一个,变成从a[x]开始往后y个
//从大的开始,快速且越往后越精确
for(int i=16;i>=0;i--)
if(y&(1<<i)) x=nex[x][i];
if(x<=n) printf("%d\n",x);
else printf("-1\n");
}
}
return 0;
}
标签:yi,输出,游览,运算,太空,int,编号,倍增,星球 来源: https://blog.csdn.net/weixin_50904510/article/details/121912408