Description
给出一个长度为 n n 的序列,初始全是 0 0 ,有次操作,第 i i 次操作将区间内所有数字与 vi v i 取较大值,最后求 ∑i=1ni⊕ai ∑ i = 1 n i ⊕ a i ,其中 ⊕ ⊕ 为异或操作
Input
首先输入一整数 T T 表示用例组数,对于每组用例输入五个整数,其中 X,Y,Z X , Y , Z 用于生成 li,ri,vi l i , r i , v i
(1≤T≤100,1≤n≤105,1≤m≤5⋅106,0≤X,Y,Z<230) ( 1 ≤ T ≤ 100 , 1 ≤ n ≤ 10 5 , 1 ≤ m ≤ 5 ⋅ 10 6 , 0 ≤ X , Y , Z < 2 30 )
Output
输出 ∑i=1ni⊕ai ∑ i = 1 n i ⊕ a i
Sample Input
4
1 10 100 1000 10000
10 100 1000 10000 100000
100 1000 10000 100000 1000000
1000 10000 100000 1000000 10000000
Sample Output
1031463378
1446334207
351511856
47320301347
Solution
每次操作 l r v l r v 即为将 ai a i 变成 max(ai,v),l≤i≤r m a x ( a i , v ) , l ≤ i ≤ r ,用线段树维护区间最小值 Min[t] M i n [ t ] ,该区间的标记 Tag[t] T a g [ t ] 以及不小于该区间标记的数字个数 Num[t] N u m [ t ] ,如果当前更新值 v v 不超过之前该区间的值,那么当前操作无效,否则清空该区间所有小于 v v 的数字,然后区间更新为,其中 Num N u m 数组的作用主要是辅助维护区间最小值,因为只有区间有部分被清空时才会存在小于 Tag T a g 的值,也即 Num[t]<r−l+1 N u m [ t ] < r − l + 1 时,会有数字需要被变成 v v ,此时区间最小值是,否则该部分不需要更新,区间最小值不变
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define INF (1<<30)
#define maxn 100005
#define ls (t<<1)
#define rs ((t<<1)|1)
int Num[maxn<<2],Min[maxn<<2],Tag[maxn<<2];
int T,n,m;
void push_up(int t)
{
Min[t]=min(Min[ls],Min[rs]);
Num[t]=Num[ls]+Num[rs];
}
void build(int l,int r,int t)
{
Num[t]=Min[t]=Tag[t]=0;
if(l==r)
{
Min[t]=Tag[t]=0,Num[t]=1;
return ;
}
int mid=(l+r)/2;
build(l,mid,ls),build(mid+1,r,rs);
push_up(t);
}
void modify(int l,int r,int t,int v)
{
if(Tag[t]>=v)return ;
Tag[t]=v;
if(Num[t]<r-l+1)
{
Min[t]=v;
Num[t]=r-l+1;
}
}
void push_down(int l,int r,int t)
{
if(!Tag[t])return ;
int mid=(l+r)/2;
modify(l,mid,ls,Tag[t]),modify(mid+1,r,rs,Tag[t]);
}
void clear(int l,int r,int t,int v)
{
if(Min[t]>=v)return ;
Tag[t]=0;
if(l==r)
{
Min[t]=Num[t]=0;
return ;
}
int mid=(l+r)/2;
clear(l,mid,ls,v),clear(mid+1,r,rs,v);
push_up(t);
}
void update(int L,int R,int l,int r,int t,int v)
{
if(Min[t]>=v)return ;
if(L<=l&&r<=R)
{
clear(l,r,t,v);
modify(l,r,t,v);
return ;
}
push_down(l,r,t);
int mid=(l+r)/2;
if(L<=mid)update(L,R,l,mid,ls,v);
if(R>mid)update(L,R,mid+1,r,rs,v);
push_up(t);
}
int query(int L,int R,int l,int r,int t)
{
if(L<=l&&r<=R)return Min[t];
int ans=INF;
push_down(l,r,t);
int mid=(l+r)/2;
if(L<=mid)ans=min(ans,query(L,R,l,mid,ls));
if(R>mid)ans=min(ans,query(L,R,mid+1,r,rs));
return ans;
}
unsigned X,Y,Z;
unsigned F()
{
X^=(X<<11);
X^=(X>>4);
X^=(X<<5);
X^=(X>>14);
unsigned W=X^(Y^Z);
X=Y;
Y=Z;
Z=W;
return Z;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d%u%u%u",&n,&m,&X,&Y,&Z);
build(1,n,1);
int mod=1<<30;
for(int i=1;i<=m;i++)
{
unsigned f1,f2,f3;
f1=F();
f2=F();
f3=F();
int L=min(f1%n+1,f2%n+1),R=max(f1%n+1,f2%n+1),v=f3%mod;
update(L,R,1,n,1,v);
}
ll ans=0;
for(int i=1;i<=n;i++)ans^=((ll)i*query(i,i,1,n,1));
printf("%lld\n",ans);
}
return 0;
}