http://acm.hdu.edu.cn/showproblem.php?pid=6356
题意:
就是每次给你用那个RNG操作,出来m个对区间进行更新的操作。
每个操作让你在L到R,把小于V的全部变为V.
让你求出把所有(i*a[I])异或起来的答案。
POINT:
你可以暴力点直接线段树更新了。根本不用多加考虑。
记一个区间最小值,若V大于这个最小值,就更新下去。
我本来n_th函数找了100个V大的区间先更新他。发现跑的更加慢了。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=5e6+10;
const int mod = 1<<30;
unsigned int x,y,z;
unsigned int a[15000020];
#define LL long long
#define lt x<<1
#define rt x<<1|1
unsigned int RNG()
{
x=x^(x<<11);
x=x^(x>>4);
x=x^(x<<5);
x=x^(x>>14);
unsigned int w = x^(y^z);
x=y;
y=z;
z=w;
return z;
}
struct node
{
int l,r;
LL v;
bool friend operator < (node a,node b)
{
return a.v<b.v;
}
}b[maxn];
LL ma[410050];
void build(int x,int l,int r)
{
ma[x]=0;
if(l==r) return;
int mid = (l+r)>>1;
build(lt,l,mid);
build(rt,mid+1,r);
}
LL ans=0;
void change(int x,int l,int r,int ll,int rr,LL vv)
{
if(ma[x]>=vv) return;
if(l==r){
ans=ans^(1LL*l*ma[x]);
ma[x]=vv;
ans=ans^(1LL*l*ma[x]);
return;
}
int mid = (l+r)>>1;
if(ll<=mid)
change(lt,l,mid,ll,rr,vv);
if(mid<rr)
change(rt,mid+1,r,ll,rr,vv);
ma[x]=min(ma[lt],ma[rt]);
}
LL query(int x,int l,int r,int pos)
{
if(l==r){
return ma[x];
}
int mid = (l+r)>>1;
if(pos<=mid)
return query(lt,l,mid,pos);
else
return query(rt,mid+1,r,pos);
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
scanf("%u%u%u",&x,&y,&z);
for(int i=1;i<=3*m;i++){
a[i]=RNG();
}
for(int i=1;i<=3*m;i+=3){
int k=(i+2)/3;
b[k].l=min(a[i]%n+1,a[i+1]%n+1);
b[k].r=max(a[i]%n+1,a[i+1]%n+1);
b[k].v=1LL*a[i+2]%mod;
}
// nth_element(b+1,b+max(1,m-100),b+m+1);
// for(int i=1;i<=m;i++)
// printf("%d %d %d\n",b[i].l,b[i].r,b[i].v);
build(1,1,n);
ans=0;
for(int i=max(1,m-100);i<=m;i++){
change(1,1,n,b[i].l,b[i].r,b[i].v);
}
int to=max(1,m-100);
for(int i=1;i<to;i++){
change(1,1,n,b[i].l,b[i].r,b[i].v);
}
printf("%lld\n",ans);
}
}