题目链接:hdu-6356.
题目描述
一个长度为
n
n
n 的整数序列
a
1
,
a
2
,
.
.
.
a
n
a_{1},a_{2},...a_{n}
a1,a2,...an,初始值均为0.
先给出
m
m
m个操作,每个操作为
l
i
,
r
i
,
v
i
l_{i}, r_{i},v_{i}
li,ri,vi,将序列
a
a
a中区间
[
l
i
,
r
i
]
[l_{i},r_{i}]
[li,ri]中小于
v
i
v_{i}
vi的所有元素更新为
v
i
v_{i}
vi.
求:
m
m
m个操作之后,
⊕
i
=
1
n
(
i
⋅
a
i
)
\oplus_{i=1}^{n} (i \cdot a_{i})
⊕i=1n(i⋅ai)。
这个公式的意思是:所有
(
i
⋅
a
i
)
(i \cdot a_{i})
(i⋅ai)的异或和(为什么还需要特别解释一下呢,因为我开始并没有注意)。
思路
-
正确思路
-
因为是比较大小,小的更新,所以记录区间最值与更新值作比较。
-
具体实现:线段树维护区间的最小值 M i n Min Min和最大值 M a x Max Max. 对于每次更新,如果 v i ≤ v_{i}\leq vi≤ M i n Min Min ,即区间最小值都大于 v i v_{i} vi,说明这个区间不需要更新;如果 v i ≥ v_{i}\geq vi≥ M a x Max Max ,即区间最大值都小于 v i v_{i} vi,说明这个区间需要全部更新。介于二者之间就继续递归。用 l a z y lazy lazy记录待更新值。如果遍历到叶子结点就更新其最大最小值: M i n = m a x ( M i n , v i ) , M a x = m a x ( M a x , v i ) . Min=max(Min, v_{i}),Max =max(Max,v_{i}). Min=max(Min,vi),Max=max(Max,vi). 这里都是取最大。
-
注意点:由父节点的 l a z y lazy lazy值传给子节点时,子节点要取最大,而不是直接赋值。
对于随机数产生函数,函数里面是 u n s i g n e d   i n t unsigned\,int unsignedint,传到函数里面时就是 i n t int int了,使用前都有取模。
求最终答案时,用区间和即可,开始我直接遍历的树,发现不得行,有些地方可能 l a z y lazy lazy还没有下放,值是不对的。结果应该用 l o n g   l o n g long\,long longlong保存。
代码
#include <bits/stdc++.h>
using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define LL long long
unsigned int X, Y, Z;
const int Mod = (1 << 30);
const int MAXN = 100005;
struct node {
int l, r;
int Min,Max;
}t[MAXN * 4];
int a[MAXN];
int lazy[MAXN * 4];
unsigned int func() { // 随机数产生器
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;
}
void push_up(int u) { // 复制时出错
t[u].Min = min(t[lson(u)].Min, t[rson(u)].Min);
t[u].Max = max(t[lson(u)].Max, t[rson(u)].Max);
return;
}
void build(int l, int r, int u) {
t[u].l = l;
t[u].r = r;
lazy[u] = -1; // 初始化
if(l == r) {
t[u].Min = t[u].Max = 0;
return;
}
int mid = (l + r) >> 1;
build(l, mid, lson(u));
build(mid+1, r, rson(u));
push_up(u);
return;
}
void push_down(int u) {
if(lazy[u] != -1) {
t[lson(u)].Min = max(lazy[u], t[lson(u)].Min);
t[rson(u)].Min = max(lazy[u], t[rson(u)].Min);
t[lson(u)].Max = max(lazy[u], t[lson(u)].Max);
t[rson(u)].Max = max(lazy[u], t[rson(u)].Max);
lazy[lson(u)] = max(lazy[u], lazy[lson(u)]); // 要和之前的lazy比较
lazy[rson(u)] = max(lazy[u], lazy[lson(u)]);
lazy[u] = -1;
}
}
void update(int L, int R, int v, int u) {
if(t[u].l == t[u].r) {
t[u].Min = max(t[u].Min, v);
t[u].Max = max(t[u].Max, v);
return;
}
if(t[u].l >= L && t[u].r <= R) { // 在中间则继续向下寻找更新
if(t[u].Min >= v) return;
if(t[u].Max <= v) {
t[u].Min = t[u].Max = v;
lazy[u] = v;
return;
}
}
if(t[u].Min >= v) return; // *QQ*
push_down(u);
int mid = (t[u].l + t[u].r) >> 1;
if(mid >= L) update(L, R, v, lson(u));
if(mid < R) update(L, R, v, rson(u));
push_up(u);
return;
}
int sum(int u, int pos) { // 必须通过函数求值,
if (t[u].l == t[u].r){
return t[u].Min;
}
int mid=(t[u].l + t[u].r) >> 1;
push_down(u); // 否则可能未被更新
if(pos <= mid) return sum(lson(u), pos);
else return sum(rson(u), pos);
}
int main() {
int T, n, m;
scanf("%d", &T);
while(T--) {
int ans = 0;
scanf("%d%d%u%u%u", &n, &m, &X, &Y, &Z);
build(1, n, 1);
for(int i = 1; i <= m; i++) {
unsigned int f1 = func() % n + 1, f2 = func() % n + 1, V = func() % Mod;
int L, R;
L = min(f1, f2); R = max(f1, f2);
update(L, R, V, 1);
}
for(int i = 1; i <= n; i++) {
ans ^= 1ll * i * sum(1,i);
}
printf("%lld\n",ans);
}
return 0;
}
错误点
基本注释的地方都曾经错过。