题目链接
题意:
Let the i-th result value of calling the above function as The i-th operation of Steve is to update aj as vi if , where
一开始给你一个序列a,里面全是0,然后有m次操作,每次操作给你[l,r],v,更新[l,r]区间,将所有区间内小于v的元素都改成v
每次操作的变量由上面那个式子产生,里面的f是由上面那个随机数函数产生
解析:
这道题......m这么大,连排序都不能排.......竟然能用最裸的在线更新的线段树过..........这也太坑了把..........
官方题解好像使用st表来做的
如果有两个操作覆盖相同的区间,我们可以保留最大的那个。对于每个操作,令d等于⌊log2(r−l+1)⌋
我们可以用两个操作和替换此操作。这样做之后,每个操作所覆盖的区间长度均为 2 的幂,这意味着长度仅有 种。剩下的只不过是,按长度递减的顺序枚举操作,将每个操作分成两个相等长度的操作,直到区间长度为一。这样做的时间复杂度为 ,空间复杂度为。
其实就是把询问的区间都分成2的幂次的长度,这样长度最多只有种,然后再用逆的st表做就可以了
st表好像要3.2s。。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
#define pb push_back
const int MAXN = 1e5+10;
const int MAXM = 5e6+10;
const ll INF = 0x3f3f3f3f;
ui X,Y,Z;
ui f[4*MAXM];
int a[MAXN];
typedef struct interval
{
int L;
int v;
}interval;
int mq[50][MAXN];
int two[50];
interval hq[MAXN];
int Log[MAXN];
inline ui RNG61()
{
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;
}
int main()
{
int t;
int kk=1<<30;
scanf("%d",&t);
int tmp=1;
Log[1]=0;
Log[2]=1;
for(int i=0;i<=20;i++) two[i]=tmp,tmp=tmp<<1;
for(int i=3;i<MAXN;i++) Log[i]=Log[i>>1]+1; //log2预处理
while(t--)
{
ll n,m;
scanf("%lld%lld%u%u%u",&n,&m,&X,&Y,&Z);
int kkk=Log[n];
for(int i=0;i<=n;i++) a[i]=0;
for(int i=0;i<=kkk;i++)
for(int j=1;j<=n;j++)
mq[i][j]=0;
for(int i=1;i<=3*m;i++)
{
f[i]=RNG61();
}
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);
int v=f[3*i]%kk;
int d=Log[r-l+1];
mq[d][l]=mq[d][l]<v?v:mq[d][l];
mq[d][r-two[d]+1]=mq[d][r-two[d]+1]<v?v:mq[d][r-two[d]+1];
}
for(int i=kkk;i>0;i--)
{
for(int j=1;j<=n;j++)
{
if(j+two[i-1]>n) break;
mq[i-1][j]=max(mq[i-1][j],mq[i][j]);
mq[i-1][j+two[i-1]]=max(mq[i-1][j+two[i-1]],mq[i][j]);
}
}
ll ans=0;
for(ll i=1;i<=n;i++)
{
ans=ans^(i*mq[0][i]);
}
printf("%lld\n",ans);
}
return 0;
}
我一开始是用单调队列代替st表的,然后必须把log进行预处理,常数优化才能过....3.3s
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int ui;
#define pb push_back
const int MAXN = 1e5+10;
const int MAXM = 5e6+10;
const ll INF = 0x3f3f3f3f;
ui X,Y,Z;
ui f[4*MAXM];
int a[MAXN];
typedef struct interval
{
int L;
int v;
}interval;
int mq[50][MAXN];
int two[50];
interval hq[MAXN];
int Log[MAXN];
inline ui RNG61()
{
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;
}
int main()
{
int t;
int kk=1<<30;
scanf("%d",&t);
int tmp=1;
Log[1]=0;
Log[2]=1;
for(int i=0;i<=20;i++) two[i]=tmp,tmp=tmp<<1;
for(int i=3;i<MAXN;i++) Log[i]=Log[i>>1]+1; //log2预处理
while(t--)
{
ll n,m;
scanf("%lld%lld%u%u%u",&n,&m,&X,&Y,&Z);
int kkk=Log[n];
for(int i=0;i<=n;i++) a[i]=0;
for(int i=0;i<=kkk;i++)
for(int j=1;j<=n;j++)
mq[i][j]=0;
for(int i=1;i<=3*m;i++)
{
f[i]=RNG61();
}
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);
int v=f[3*i]%kk;
int d=Log[r-l+1];
mq[d][l]=mq[d][l]<v?v:mq[d][l];
mq[d][r-two[d]+1]=mq[d][r-two[d]+1]<v?v:mq[d][r-two[d]+1];
}
int head,tail;
head=tail=0;
for(int i=kkk;i>=0;i--)
{
head=tail=0;
for(int j=1;j<=n;j++)
{
while(head<tail&&hq[tail-1].v<=mq[i][j])
tail--;
hq[tail++]=interval{j,mq[i][j]};
if(head<tail)
a[j]=max(hq[head].v,a[j]);
if(j-two[i]+1>=1)
{
while(head<tail&&hq[head].L<=j-two[i]+1)
head++;
}
}
}
ll ans=0;
for(ll i=1;i<=n;i++)
{
ans=ans^(i*a[i]);
}
printf("%lld\n",ans);
}
return 0;
}
最裸的线段树,2.9s.......这个是最快的
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
#define lch root<<1
#define rch root<<1|1
typedef unsigned int ui;
typedef long long ll;
const int MAXN = 1e5+10;
const int MAXM = 5e6+10;
const ll INF = 0x3f3f3f3f;
ui X,Y,Z;
ui f[4*MAXM];
int a[MAXN];
int Btree[MAXN*4];
inline ui RNG61()
{
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 updateone(int root,int s1,int e1,int l,int r,int val) //维护区间最小值
{
if(e1<l||s1>r) return;
if(s1>e1)return;
if(Btree[root]>val) return;
if(s1==e1)
{
Btree[root]=val;
a[s1]=val;
return;
}
//pushDown(root);
int mid=(s1+e1)>>1;
if(l<=mid)
updateone(root<<1,s1,mid,l,r,val);
if(mid+1<=r)
updateone((root<<1)|1,mid+1,e1,l,r,val);
Btree[root]=min(Btree[lch],Btree[rch]);
//push_up(root);
}
int main()
{
int t;
int kk=1<<30;
scanf("%d",&t);
while(t--)
{
ll n,m;
scanf("%lld%lld%u%u%u",&n,&m,&X,&Y,&Z);
for(int i=0;i<=n;i++) a[i]=0;
memset(Btree,0,sizeof(Btree));
for(int i=1;i<=3*m;i++)
{
f[i]=RNG61();
}
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);
int v=f[3*i]%kk;
updateone(1,1,n,l,r,v);
}
ll ans=0;
for(ll i=1;i<=n;i++)
{
ans=ans^(i*a[i]);
}
printf("%lld\n",ans);
}
}