题意是给定一个随机数生成器,得到l, r, val表示将区间[l, r]内比val小的元素修改为val
解法有两种
第一种是线段树解法,我们就用线段树维护一个区间最小值,当val比区间的minn还小那么就不更新,否则向下暴力更新。因为数据是随机生成的,所以暴力更新并不会被卡。开始的想法是将所有操作按val从大到小排序,那么我们每个点就只会被更新一次,但是由于操作次数太多,排序时间大于计算答案的时间。
#include
using namespace std;
#define MIN(a,b) (a)<(b)?(a):(b)
#define fr first
#define se second
typedef unsigned ui;
typedef long long LL;
const int maxn=1e5+5;
const int mod=1<<30;
ui minn[maxn<<2],a[maxn];
ui x,y,z;
int n,m,maxx;
ui fun()
{
x^=x<<11;
x^=x>>4;
x^=x<<5;
x^=x>>14;
ui t=x^(y^z);
x=y;
y=z;
z=t;
return z;
}
void update(int rt,int L,int R,int l,int r,ui val)
{
if(L==R){
if(minn[rt]return;
}else if(minn[rt]>=val) return;
int mid=L+R>>1;
if(r<=mid) update(rt<<1,L,mid,l,r,val);
else if(l>mid) update(rt<<1|1,mid+1,R,l,r,val);
else{
update(rt<<1,L,mid,l,mid,val);
update(rt<<1|1,mid+1,R,mid+1,r,val);
}
minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%u%u%u",&n,&m,&x,&y,&z);
for(int i=1;i<=m;i++){
int l=fun()%n+1;
int r=fun()%n+1;
if(l>r) swap(l,r);
ui val=fun()%mod;
update(1,1,n,l,r,val);
}
long long ans=0;
for(int i=1;i<=n;i++){
ans^=i*(LL)a[i];
}
printf("%lld\n",ans);
memset(minn,0,sizeof minn);
}
return 0;
}
第二种是用倍增的方法。普通的ST表写法:dp[i][j]=max{dp[i][j-1],dp[i+(1<
ans=max{dp[i][len],dp[r-(1<
[l, r]
,那么肯定会对dp[l][len]
和dp[r-(1<
dp[l][len]
和dp[r-(1<
感觉这种算法的使用范围较小,适合与将区间赋值,且与区间极值存在关系。
#include
using namespace std;
typedef long long LL;
typedef unsigned ui;
const int maxn=1e5+5;
const ui mod=1<<30;
int n,m;
ui x,y,z;
ui dp[maxn][20];
int logdis[maxn];
ui fun()
{
x^=x<<11;
x^=x>>4;
x^=x<<5;
x^=x>>14;
ui w=x^(y^z);
x=y;
y=z;
z=w;
return z;
}
void update(int l,int r,ui val)
{
int len=logdis[r-l+1];
dp[l][len]=max(dp[l][len],val);
dp[r-(1<1][len]=max(dp[r-(1<1][len],val);
}
int main()
{
for(int i=2;i>1]+1;
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%u%u%u",&n,&m,&x,&y,&z);
for(int i=1;i<=m;++i){
int l=fun()%n+1;
int r=fun()%n+1;
if(l>r) swap(l,r);
ui val=fun()%mod;
update(l,r,val);
}
for(int j=logdis[n];j>=1;j--){
for(int i=1;i+(1<1<=n;i++){
dp[i][j-1]=max(dp[i][j-1],dp[i][j]);
dp[i+(1<1)][j-1]=max(dp[i+(1<1)][j-1],dp[i][j]);
}
}
LL ans=0;
for(int i=1;i<=n;++i){
ans^=i*(LL)dp[i][0];
}
printf("%lld\n",ans);
for(int i=0;i<=n;++i){
for(int j=0;j<=logdis[n]+1;++j) dp[i][j]=0;
}
}
return 0;
}