G.Glad You Came(逆序ST)
rng61()函数生成长度为3*m(m<=5e6)的f[],
给定一个长度为n(n<=1e5)的a[],初始全为0,
通过f有关的函数得到m次区间赋值操作,
第i次操作[li,ri,vi],表示将a[]的[l,r]赋值为max(a[i],v),
即每个点保留历史时刻被赋值的最大值,求
思路来源
马老师代码
题解
考虑正向ST的过程,RMQ时拆成两段分别询问最大值,再取max
而逆序ST,更新时先更新RMQ对应的这两段的最大值,
最后倒序ST,用长的完整区间,去更新两个半段区间的最大值
最后输出每个单点的最大值
长度是2的几次幂用lg[]数组预处理一下,
不要写函数避免调用,常数写小点
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
typedef unsigned us;
const int mod=1<<30;
const int N=1e5+10;
const int M=5e6+10;
ll ans;
int t,l,r,v;
int n,m,d,mn,mx;
us w,x,y,z,f[3*M];
int len,k,lg[N],dp[N][18];
us rng61()
{
x=x^(x<<11);
x=x^(x>>4);
x=x^(x<<5);
x=x^(x>>14);
w=x^(y^z);
x=y;y=z;z=w;
return z;
}
int main()
{
scanf("%d",&t);
for(int i=2;i<N;++i)
lg[i]=lg[i>>1]+1;
while(t--)
{
ans=len=0;
scanf("%d%d%u%u%u",&n,&m,&x,&y,&z);
int mx=max(n,3*m);
for(int i=1;i<=mx;++i)
f[i]=rng61();
for(int i=1;i<=m;++i)
{
mn=(f[3*i-2]%n)+1;
mx=(f[3*i-1]%n)+1;
l=min(mn,mx);
r=max(mn,mx);
v=f[3*i]%mod;
k=lg[r-l+1];
r=r-(1<<k)+1;
dp[l][k]=max(dp[l][k],v);
dp[r][k]=max(dp[r][k],v);
d=max(d,k);
}
for(int len=d;len>=1;--len)
{
for(int i=1,now=(1<<len);i+now-1<=n;++i)
{
dp[i][len-1]=max(dp[i][len-1],dp[i][len]);
dp[i+(now>>1)][len-1]=max(dp[i+(now>>1)][len-1],dp[i][len]);
}
}
for(int i=1;i<=n;++i)
ans=ans^(1ll*i*dp[i][0]);
printf("%lld\n",ans);
memset(dp,0,sizeof dp);
}
return 0;
}