题意描述:

给出数据生成规则生成m组L,R,V,表示区间【L,R】中小于V的都更新为V。

求最后对全部的a[i]*i 取异或和的结果

题目分析:

ST表:

st[i][j]表示从i开始的2^j个数的最大值     //ST[N][logN]

第二维的大小是logN,可以理解为ST表的层数,第 j 层的每个位置维护从该位置开始2^j 个数的信息

那么每次更新【L,R】,找到最大的2^k的k小于等于R-L+1

只需要更新st[L][k]和st[R-(1<<k)+1][k]就能完整地把区间【L,R】给覆盖住,这样的更新操作需要的时间只有O(1)

在m次操作进行完成之后,这个st表上零零散散的有很多区间最大值,叠在各个层

我们从最高层(也就是维护着最后续区间的层)开始向下递推更新最大值,直至最底层,复杂度O(NlogN)

递推完成之后的每个st[i][0]就是操作后每个位置的数值了,查询O(1)

AC代码:

#include<iostream>
#include<stdio.h>
#define ll long long
using namespace std;
unsigned x,y,z,w,n,m;
int st[200005][18]; //st[i][j]表示从i开始的2^j个数的最大值
int lg[200005];
inline unsigned rng61(){
x^=(x<<11); x^=(x>>4); x^=(x<<5); x^=(x>>14);
w=(x^y^z); x=y; y=z; z=w;
return z;
}
inline void init(){//log2打表
lg[0] = -1;
for(int i = 1;i< 100005;i++)
lg[i] = lg[i-1] + ((i&(i-1)) == 0);
}
inline void getop(int &l,int &r,int &v){
unsigned f1=rng61(),f2=rng61();
l=min(f1%n+1,f2%n+1), r=max(f1%n+1,f2%n+1);
v=rng61()%1073741824;
}
int main(){
int t,l,r,v,k;
init();
scanf("%d",&t);
while(t--){
scanf("%d %d %d %d %d",&n,&m,&x,&y,&z);
for(int i=0;i<m;i++){
getop(l,r,v);
k=lg[r-l+1];
//区间[l,r]的值对v取最大值更新
st[l][k]=max(st[l][k],v);
st[r-(1<<k)+1][k]=max(st[r-(1<<k)+1][k],v);
}
for(int i=lg[n];i>=1;i--){//从区间长度最大向下递推,类似线段树pushdown
for(int j=1;j<=n;j++){
st[j][i-1]=max(st[j][i-1],st[j][i]);
st[j+(1<<(i-1))][i-1] = max(st[j+(1<<(i-1))][i-1],st[j][i]);
st[j][i]=0;
}
}
ll ans=0;
for(ll i = 1;i<= n;i++){
ans^= (st[i][0]*i);
st[i][0] = 0;
}
printf("%lld\n",ans);
}
return 0;
}