一、思路
线段树维护一个区间最小值,然后对于每次操作,做区间更新即可。要注意的是,在更新的时候,记得剪枝:如果当前更新的值$v \le minv$(minv为当前线段树节点所管辖区间的最小值),直接返回。否则,TLE。运行时间1500+ms,比标程2800+ms快将近两倍。
二、代码
#includeusing namespace std;#define min(x, y) (x < y ? x : y)#define max(x, y) (x > y ? x : y)#define MAXN 100100unsigned X, Y, Z;struct node { int mv, lazy;} data[MAXN * 4];int n, m;inline void down(int rt) { if(data[rt].lazy) { int lch = rt << 1, rch = rt << 1 | 1; if(data[lch].lazy < data[rt].lazy)data[lch].lazy = data[rt].lazy; if(data[lch].mv < data[rt].lazy)data[lch].mv = data[rt].lazy; if(data[rch].lazy < data[rt].lazy)data[rch].lazy = data[rt].lazy; if(data[rch].mv < data[rt].lazy)data[rch].mv = data[rt].lazy; data[rt].lazy = 0; }}inline void update(int ul, int ur, int v, int rt = 1, int l = 1, int r = n) { if(l > ur || r < ul)return; if(v <= data[rt].mv)return; if(l >= ul && r <= ur) { if(data[rt].mv < v)data[rt].mv = v, data[rt].lazy = v; return; } down(rt); int mid = (l + r) >> 1; update(ul, ur, v, rt << 1, l, mid); update(ul, ur, v, rt << 1 | 1, mid + 1, r); data[rt].mv = min(data[rt << 1].mv, data[rt << 1 | 1].mv);}inline int query(int x, int rt = 1, int l = 1, int r = n) { if(l == r)return data[rt].mv; down(rt); int mid = (l + r) >> 1; if(x <= mid)return query(x, rt << 1, l, mid); else return query(x, rt << 1 | 1, mid + 1, r);}inline unsigned rng61() { 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() {// freopen("1007.in", "r", stdin);// freopen("1007.out", "w", stdout); int T, mod = (1 << 30) - 1; scanf("%d", &T); for(int ca = 0; ca < T; ++ca) { scanf("%d%d%u%u%u", &n, &m, &X, &Y, &Z); memset(data, 0, sizeof(data[0]) * ((n << 2) + 5)); for(int jj = 0; jj < m; ++jj) { unsigned f1 = rng61(), f2 = rng61(); if(f1 >= n)f1 %= n; if(f2 >= n)f2 %= n; int ul = f1 + 1, ur = f2 + 1, v = rng61() & mod; if(ul > ur)swap(ul, ur); update(ul, ur, v); } long long ans = 0; for(int i = 1; i <= n; ++i)ans ^= 1LL * i * query(i); printf("%lld\n", ans); } return 0;}