Glad You Came
Output file: standard output
Time limit: 5 seconds
Memory limit: 256 mebibytes
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
<
<
<script type="math/tex" id="MathJax-Element-1"><</script>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≤10^5, 1≤m≤5⋅10^6, 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⋅107
5
⋅
10
7
.
Output
For each test case, output the answer in one line.
Sample Input | Sample Output |
---|---|
4 1 10 100 1000 10000 10 100 1000 10000 100000 100 1000 10000 100000 1000000 1000 10000 100000 1000000 10000000 | 1031463378 1446334207 351511856 47320301347 |
a序列长度为n,开始时都为0,m次操作(l,r,v),每次把a的[l,r]当中小于v的数改成v,最后输出异或和,其实相当于求a序列。
观察可以发现,m比n大很多,所以很多操作都是无效的。
设置一个阈值threshold,当某次操作的v小于阈值时则忽略该次操作。经过打表可以发现,将m分段之后设置不同的阈值,剩下的操作可以覆盖整个a数组。
如果某次操作的l,r比较偏向边界,如l<=100,r<=n-100,则因为对a数组边缘部分的修改可能很少(l,r完全随机,l很小或r很大的情况很少,此时的v大于阈值的可能就更少了),所以也不能忽略,否则a数列的前面几个位置和最后几个位置很可能一次更新也没有。
这样过滤掉大多数操作之后,可以直接线段树暴力修改查询。
最后只跑了2000ms.
过题之后,队友惊呼,这TM也能过!
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#include <assert.h>
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef pair<int,int> pp;
const int maxn=100005,maxk=1000005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
int num=0;
struct node {
int l,r,v;
};
node a[maxk];
bool cmp(node a,node b) {
return a.v>b.v;
}
unsigned x,w,y,z;
unsigned prand() {
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;
}
struct Tree {
int lc,rc,l,r,max,tag;
};
Tree tree[4*maxn];
void build(int now,int l,int r) {
// cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].lc << ' ' << tree[now].rc << endl;
tree[now].l=l;
tree[now].r=r;
tree[now].tag=0;
tree[now].max=0;
if (l!=r) {
num++;
tree[now].lc=num;
build(num,l,(l+r)/2);
num++;
tree[now].rc=num;
build(num,(l+r)/2+1,r);
}
// cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].lc << ' ' << tree[now].rc << endl;
}
void update (int now,int l,int r,int c) {
// cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].max << ' ' << tree[now].tag << endl;
if (tree[now].l>=l&&tree[now].r<=r) {
tree[now].max=max(c,tree[now].max);
} else {
if (l<=(tree[now].l+tree[now].r)/2)
update(tree[now].lc,l,r,c);
if (r>(tree[now].l+tree[now].r)/2)
update(tree[now].rc,l,r,c);
}
}
ll findans (int now) {
// cout << now << ' ' << tree[now].l << ' ' << tree[now].r << ' ' << tree[now].max << endl;
if (tree[now].l==tree[now].r) {
return (ll)tree[now].l*(ll)tree[now].max;
} else {
tree[tree[now].lc].max=max(tree[tree[now].lc].max,tree[now].max);
tree[tree[now].rc].max=max(tree[tree[now].rc].max,tree[now].max);
ll ans=findans(tree[now].lc);
ans^=findans(tree[now].rc);
return ans;
}
}
int main() {
int cas;
scanf("%d",&cas);
while (cas--) {
int n,m;
scanf("%d%d",&n,&m);
unsigned threshold;
if (m<5000) {
threshold=-1;
} else if (m<10000) {
threshold=5e8;
} else if (m<100000) {
threshold=9e8;
} else if (m<1000000) {
threshold=1020000000;
} else threshold=1060000000;
unsigned f1,f2,l,r,v;
scanf("%u%u%u",&x,&y,&z);
int cnt=0;
for (int i=1;i<=m;i++) {
f1=prand();f2=prand();
l=min(f1%n+1,f2%n+1);
r=max(f1%n+1,f2%n+1);
v=prand()%(1<<30);
if (v>threshold||(l<=100||r+100>=n)) {
a[++cnt].l=l;a[cnt].r=r;a[cnt].v=v;
}
}
num=1;
build(1,1,n);
for (int i=1;i<=cnt;i++) {
update(1,a[i].l,a[i].r,a[i].v);
}
ll ans=findans(1);
printf("%lld\n",ans);
}
return 0;
}