题目链接:HDU-6356-Glad You Came
(一)题面:
Problem Description
Steve has an integer array a of length n (1-based). He assigned all the elements as zero at the beginning. After that, he made m operations, each of which is to update an interval of a with some value. You need to figure out ⨁ni=1(i⋅ai) after all his operations are finished, where ⨁ means the bitwise exclusive-OR operator.
In order to avoid huge input data, these operations are encrypted through some particular approach.
There are three unsigned 32-bit integers X,Y and Z which have initial values given by the input. A random number generator function is described as following, where ∧ means the bitwise exclusive-OR operator, << means the bitwise left shift operator and >> means the bitwise right shift operator. Note that function would change the values of X,Y and Z after calling.
Let the i-th result value of calling the above function as fi (i=1,2,⋯,3m). The i-th operation of Steve is to update aj as vi if aj<vi (j=li,li+1,⋯,ri), where
Input
The first line contains one integer T, indicating the number of test cases.
Each of the following T lines describes a test case and contains five space-separated integers n,m,X,Y and Z.
1≤T≤100, 1≤n≤1e5, 1≤m≤5⋅1e6, 0≤X,Y,Z<2^30.
It is guaranteed that the sum of n in all the test cases does not exceed 106 and the sum of m in all the test cases does not exceed 5⋅1e7.
Output
For each test case, output the answer in one line.
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
(二)题意:
有一个长度为n的序列,初始值全为0,然后给定m个操作,每个操作指定区间[L,R]和值v,然后将该区间中所有小于v的值替换成v。其中每次操作的L、R和v由一个给定的“随机”函数生成。求经过m次操作以后序列中各个<值与其下标的乘积>的异或值(看原题中表达式更清楚)。
(三)题解:
对于每次操作,我们都会将区间中小于v的值变为v,那么我们就维护一下区间的最小值,当区间的最小值小于v时,将该区间的最小值更新为v,然后就只是一个简单的线段树的区间维护最小值而已了,打个lazy即可。由于这里的数据随机给出,所以线段树实际上的效率还比较高。
(四)代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#define LL long long
#define UINT unsigned int
#define MOD (1<<30)
using namespace std;
const int maxn=1e5+10;
UINT F[maxn*150];
UINT X,Y,Z;
UINT FUNC(){
X=X^(X<<11);X=X^(X>>4);
X=X^(X<<5);X=X^(X>>14);
UINT W=X^(Y^Z);
X=Y;Y=Z;Z=W;
return Z;
}
struct Tree{
int l,r,lazy,_min;
int mid(){return (l+r)>>1;}
}tree[maxn<<2];
void PushDown(int rt){
if(tree[rt].lazy){
if(tree[rt<<1]._min<tree[rt].lazy){
tree[rt<<1].lazy=tree[rt].lazy;
tree[rt<<1]._min=tree[rt].lazy;
}
if(tree[rt<<1|1]._min<tree[rt].lazy){
tree[rt<<1|1].lazy=tree[rt].lazy;
tree[rt<<1|1]._min=tree[rt].lazy;
}
tree[rt].lazy=0;
}
}
void BuildTree(int rt,int l,int r){
tree[rt].l=l;tree[rt].r=r;
tree[rt].lazy=tree[rt]._min=0;
if(l==r)return;
int m=tree[rt].mid();
BuildTree(rt<<1,l,m);
BuildTree(rt<<1|1,m+1,r);
}
void UpdataTree(int rt,int l,int r,int v){
if(l<=tree[rt].l&&tree[rt].r<=r){
tree[rt].lazy=v;
tree[rt]._min=v;
return;
}
PushDown(rt);
int m=tree[rt].mid();
if(r<=m&&tree[rt<<1]._min<v)UpdataTree(rt<<1,l,r,v);
else if(l>m&&tree[rt<<1|1]._min<v)UpdataTree(rt<<1|1,l,r,v);
else if(r>m&&l<=m){
if(tree[rt<<1]._min<v)UpdataTree(rt<<1,l,m,v);
if(tree[rt<<1|1]._min<v)UpdataTree(rt<<1|1,m+1,r,v);
}
tree[rt]._min=min(tree[rt<<1]._min,tree[rt<<1|1]._min);
}
LL ans=0;
void QueryTree(int rt,int l,int r){
if(l==r){
ans^=(1ll*l*tree[rt]._min);
return;
}
PushDown(rt);
int m=tree[rt].mid();
QueryTree(rt<<1,l,m);
QueryTree(rt<<1|1,m+1,r);
}
int main(){
// freopen("in.txt","r",stdin);
int T,n,m;
scanf("%d",&T);
while(T--){
scanf("%d%d%u%u%u",&n,&m,&X,&Y,&Z);
for(int i=1;i<=3*m;i++)F[i]=FUNC();
BuildTree(1,1,n);
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]%MOD;
if(tree[1]._min<v)UpdataTree(1,l,r,v);
}
QueryTree(1,1,n);
printf("%lld\n",ans);ans=0;
}
return 0;
}
(五)总结:
水题啊水题