CF703D Mishka and Interesting sum
Posted luckyblock
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF703D Mishka and Interesting sum相关的知识,希望对你有一定的参考价值。
知识点:线段树
原题面:Codeforces
题意简述
给定一长度为 (n) 的数列 (a),给定 (m) 次询问。
每次询问给定区间内,出现过偶数次的权值 的异或和。
(1le n,mle 10^6),(1le a_ile 10^9)。
分析题意
根据异或的自反性,一个区间内所有数的异或和,为区间内出现过 奇数次 的权值的异或和。
再根据异或的自反性,一个区间的答案,即为区间出现过的权值的异或和,异或上区间内出现过 奇数次 的权值的异或和。
即有下式:
显然区间内所有数的异或和可前缀和维护。
考虑如何求得区间内出现过的权值的异或和。
维护的信息不便于删除,套路地考虑扫描线。
令线段树下标为 (r) 的叶节点维护区间 ([l,r]) 的信息。
其中 (l) 为当前扫描到的左端点。
维护 (nex_{i}),表示 (a_i) 右侧等于 (a_i) 的第一个数,若不存在则为 (n+1)。
则对于一个位置 (i),其影响的范围为 ([i,nex_i)),他的出现令该区间权值的异或和 (oplus a_i)。
初始 (l=1) 时,按上述方法将所有位置插入线段树中,构造出初始状态。
当 (l+1) 时,删去了 (a_{l-1}) 显然仅有 ([l, nex_{l-1})) 部分受到影响,根据异或的自反性,令该区间异或和 (oplus a_{l-1}) 即可。
在 (l) 右移的同时回答询问。
线段树支持区间异或即可。
单次 (l+1),单次查询的复杂度均为 (O(log n))。
总复杂度 (O((n+m)log n))。
爆零小技巧
注意修改区间的开闭情况。
代码实现
//知识点:线段树
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <map>
#define LL long long
const int kMaxn = 1e6 + 10;
//=============================================================
struct Query {
int l, r, id;
} q[kMaxn];
int n, m, a[kMaxn], nex[kMaxn], sum[kMaxn], ans[kMaxn];
std::map <int, int> pos;
//=============================================================
inline int read() {
int f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == ‘-‘) f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ ‘0‘);
return f * w;
}
void Chkmax(int &fir_, int sec_) {
if (sec_ > fir_) fir_ = sec_;
}
void Chkmin(int &fir_, int sec_) {
if (sec_ < fir_) fir_ = sec_;
}
bool CompareQuery(Query fir, Query sec) {
if (fir.l != sec.l) return fir.l < sec.l;
return fir.r < sec.r;
}
namespace Seg {
#define ls (now_<<1)
#define rs (now_<<1|1)
#define mid ((L_+R_)>>1)
int sum[kMaxn << 2], tag[kMaxn << 2];
void Pushdown(int now_) {
if (! tag[now_]) return ;
sum[ls] ^= tag[now_]; tag[ls] ^= tag[now_];
sum[rs] ^= tag[now_]; tag[rs] ^= tag[now_];
tag[now_] = 0;
}
void Modify(int now_, int L_, int R_, int l_, int r_, int val_) {
if (l_ <= L_ && R_ <= r_) {
sum[now_] ^= val_;
tag[now_] ^= val_;
return ;
}
Pushdown(now_);
if (l_ <= mid) Modify(ls, L_, mid, l_, r_, val_);
if (r_ > mid) Modify(rs, mid + 1, R_, l_, r_, val_);
}
int Query(int now_, int L_, int R_, int pos_) {
if (L_ == R_) return sum[now_];
Pushdown(now_);
if (pos_ <= mid) return Query(ls, L_, mid, pos_);
return Query(rs, mid + 1, R_, pos_);
}
void Debug(int now_, int L_, int R_) {
if (L_ == R_) {
printf("%d ", sum[now_]);
return ;
}
Pushdown(now_);
Debug(ls, L_, mid);
Debug(rs, mid + 1, R_);
}
#undef ls
#undef rs
#undef mid
}
void Prepare() {
n = read();
for (int i = 1; i <= n; ++ i) {
a[i] = read();
sum[i] = sum[i - 1] ^ a[i];
}
for (int i = n; i >= 1; -- i) {
if (pos.count(a[i])) {
nex[i] = pos[a[i]];
} else {
nex[i] = n + 1;
}
pos[a[i]] = i;
}
for (int i = 1; i <= n; ++ i) {
Seg::Modify(1, 1, n, i, nex[i] - 1, a[i]);
}
m = read();
for (int i = 1; i <= m; ++ i) {
q[i] = (Query) {read(), read(), i};
}
std::sort(q + 1, q + m + 1, CompareQuery);
}
//=============================================================
int main() {
Prepare();
int i = 1;
for (; i <= m; ++ i) {
if (q[i].l > 1) break;
ans[q[i].id] = sum[q[i].r] ^ sum[q[i].l - 1] ^ Seg::Query(1, 1, n, q[i].r);
}
for (int l = 2; l <= n; ++ l) {
Seg::Modify(1, 1, n, l, nex[l - 1] - 1, a[l - 1]);
for (; i <= m; ++ i) {
if (q[i].l > l) break;
ans[q[i].id] = sum[q[i].r] ^ sum[q[i].l - 1] ^ Seg::Query(1, 1, n, q[i].r);
}
}
for (int i = 1; i <= m; ++ i) {
printf("%d
", ans[i]);
}
return 0;
}
以上是关于CF703D Mishka and Interesting sum的主要内容,如果未能解决你的问题,请参考以下文章
CF703D Mishka and Interesting sum
[CF 703D]Mishka and Interesting sum
CF703D Mishka and Interesting sum
CF703D Mishka and Interesting sum(求区间出现次数偶数次数的异或和)