HDU 6356 Glad You Came --- RMQ 反向ST表 (2018多校5)

本文介绍了一种利用ST表进行区间更新并求解数组异或和的问题解决方法。通过预处理f函数值,实现高效的区间更新操作。最终计算数组元素与其下标异或和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出 n m x y z,表示有一个含有 n 个元素的数组,有 m 次操作,这 m 次操作要通过一个函数的结果得出的

使用给出的 x y z 可以把 f函数 1 到 3 * m 的值先算出来,然后m次操作里使用 f 函数的值去算出 l   r   v

操作就是对数组上 [ l , r ] 的区间做更新,如果  v > a[ i ] 那么就把 a [ i ] 的值更新为 v

最后求数组里的数 * i 后的异或和

思路:反向地使用 ST表,对区间进行更新的时候,直接更新 ST 表最上层的相互率最大且相互不超出的两个区间

比如现在更新的区间 是  [ 5 , 11 ]  这个区间长度为 7 ,那么要更新的两个区间就是 [ 5 , 9 ]   和  [ 7 , 11 ]   因为小于 7 的最大的2的此方数 为 4,所以两个子区间长度要为 4 

这样把所有操作都做完之后,从最上层开始往下更新,把值往下更新,最后更新到最底层的时候数组每个位置的值就出来了

#include<bits/stdc++.h>
using namespace std;
#define ui unsigned int
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))

const int maxn = 1e5 + 5;
const int maxm = (5e6 + 5) * 3;
const int mod = 1 << 30;
ui x,y,z,st[maxn][20],f[maxm];
int logs[maxn];

ui func(){
	x = x ^ (x << 11);
	x = x ^ (x >> 4);
	x = x ^ (x << 5);
	x = x ^ (x >> 14);
	ui w = x ^ (y ^ z);
	x = y;
	y = z;
	z = w;
	return z;	
}

void init(){
	logs[0] = -1;
	for(int i = 1;i < maxn;i++){
		logs[i] = logs[i >> 1] + 1;
	}	
} 

int main(){
	int T,n,m;
	init();
	scanf("%d",&T);
	while(T--){
		scanf("%d %d %u %u %u",&n,&m,&x,&y,&z);
		mem(st,0);
		for(int i = 1;i <= 3 * m;i++){
			f[i] = func();
		}
		int maxbit = 0;
		for(int i = 1;i <= m;i++){
			int l = min((f[3 * i - 2] % n) + 1,(f[3 * i - 1] % n) + 1);
			int r = max((f[3 * i - 2] % n) + 1,(f[3 * i - 1] % n) + 1);
			ui v = f[3 * i] % mod;
			int k = logs[r - l + 1];
			st[l][k] = max(st[l][k],v);
			st[r - (1 << k) + 1][k] = max(st[r - (1 << k) + 1][k],v);
			maxbit = max(maxbit,k);
		}
		for(int i = maxbit;i >= 1;i--){
			int k = 1 << i;
			for(int j = 1;j <= n;j++){
				if(j + k - 1 > n)
					break;
				st[j][i - 1] = max(st[j][i - 1],st[j][i]);
				st[j + (k >> 1)][i - 1] = max(st[j + (k >> 1)][i - 1],st[j][i]);
			}
		} 
		ll ans = 0;
		for(int i = 1;i <= n;i++){
			ans ^= 1ll * st[i][0] * i;
		}
		printf("%lld\n",ans);
	}	
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值