题目:
小睿睿的n个妹纸排成一排,每个妹纸有一个颜值val[i]。有m个询问,对于每一个询问,小睿睿想知道区间[L,R]颜值最高而编号最小的妹纸是哪一个
分析:
题意只求区间最大值的下标,O(n*logn+m*logn)的线段树肯定会T,没有修改操作,首先选择O(nlogn+m)的ST表;考虑在初始化DP[i][j]时,同时dp[i][j]记录DP[i][j]的值来自那里
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxn = 1e5+15;
int DP[maxn][20],arr[maxn],dp[maxn][20];
void init(int n)
{
for(int i=1;i<=n;i++){
DP[i][0]=arr[i];
dp[i][0] = i;
}
for(int j=1; (1<<j)<=n; ++j){
for(int i=1; i+(1<<j)-1<=n; ++i){
if(DP[i][j-1] >= DP[i+(1<<(j-1))][j-1]){
DP[i][j] = DP[i][j-1];
dp[i][j] = dp[i][j-1];
}else{
DP[i][j] = DP[i+(1<<(j-1))][j-1];
dp[i][j] = dp[i+(1<<(j-1))][j-1];
}
}
}
}
inline int result(int l,int r)
{
int k=trunc(log2(r*1.0-l+1));
return DP[l][k] >= DP[r-(1<<k)+1][k] ? dp[l][k] : dp[r-(1<<k)+1][k];
}
void generate_array(int n,int seed)
{
unsigned x = seed;
for (int i=1;i<=n;++i)
{
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
arr[i] = x % 100;
}
}
int generate_ask(int n,int m,int seedx,int seedy)
{
int res = 0,lastans=0;
unsigned x = seedx,y = seedy;
for (int i=1;i<=m;++i)
{
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
y ^= y << 13;
y ^= y >> 17;
y ^= y << 5;
int L=(x^lastans)%n+1,R=(y^lastans)%n+1;
if (L>R) swap(L,R);
lastans = result(L,R);
res ^= lastans;
}
return res;
}
int main()
{
int n,m,seedx,seedy,seed;
cin>>n>>m>>seed>>seedx>>seedy;
generate_array(n,seed);
init(n);
cout<<generate_ask(n,m,seedx,seedy)<<endl;
return 0;
}