太空旅行:倍增+位运算

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;
}

上一篇:python机器学习之分类预测


下一篇:FMR,RR(Registeration Recall)3DMatch数据集的评估指标