int n;
namespace MoAlgorithm {
static const int MAXM = 3e5 + 10;
static const int MAXN = 3e5 + 10;
int n, m, BLOCK;
struct Node {
int l, r, id;
bool operator<(const Node &node) const {
if (l / BLOCK != node.l / BLOCK)
return l < node.l;
if ((l / BLOCK) & 1)
return r < node.r;
return r > node.r;
}
} node[MAXM];
int ans[MAXM];
int L, R;
int a[MAXN];
int cnt[MAXN];
int cntcnt[MAXN];
int curans;
void add(int x) {
x = a[x];
--cntcnt[cnt[x]];
if (cnt[x] == curans)
++curans;
++cnt[x];
++cntcnt[cnt[x]];
}
void sub(int x) {
x = a[x];
--cntcnt[cnt[x]];
if (cnt[x] == curans && cntcnt[cnt[x]] == 0)
--curans;
--cnt[x];
++cntcnt[cnt[x]];
}
void Solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
cnt[i] = 0;
cntcnt[0] = n;
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
BLOCK = (int) ceil(pow(n, 0.5));
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &node[i].l, &node[i].r);
node[i].id = i;
}
sort(node + 1, node + 1 + m);
L = 1, R = 0, curans = 0;
for (int i = 1; i <= m; ++i) {
while (L > node[i].l)
--L, add(L);
while (R < node[i].r)
++R, add(R);
while (L < node[i].l)
sub(L), ++L;
while (R > node[i].r)
sub(R), --R;
int len = R - L + 1;
if (curans <= (len + 1) / 2)
ans[node[i].id] = 1;
else
ans[node[i].id] = 2;
}
for (int i = 1; i <= m; ++i)
printf("%d
", ans[i]);
}
}
CF617E - XOR and Favorite Number
统计[L,R]内有多少对(i,j)满足ij之间的所有元素异或起来等于某个常数k。这里的区间[L,R]中夹着的异或前缀和是[p[L-1],p[R]]这么多个,所以一开始初始化的时候虽然是空集但是是有p[0]在,往左拓展区间的时候是把L-1加进来,往右的时候正常把R加进来。
namespace MoAlgorithm {
static const int MAXM = 1e5 + 10;
static const int MAXN = 1e5 + 10;
int n, m, BLOCK;
struct Node {
int l, r, id;
bool operator<(const Node &node) const {
if (l / BLOCK != node.l / BLOCK)
return l < node.l;
if ((l / BLOCK) & 1)
return r < node.r;
return r > node.r;
}
} node[MAXM];
ll ans[MAXM];
int L, R;
ll curans;
int a[MAXN], p[MAXN];
int k, cnt[(1 << 20)];
void add(int x) {
curans += cnt[k ^ p[x]];
++cnt[p[x]];
}
void sub(int x) {
--cnt[p[x]];
curans -= cnt[k ^ p[x]];
}
void Solve() {
ms(cnt);
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
p[i] = p[i - 1] ^ a[i];
}
BLOCK = (int)ceil(pow(n, 0.5));
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &node[i].l, &node[i].r);
node[i].id = i;
}
sort(node + 1, node + 1 + m);
L = 1, R = 0, curans = 0, cnt[p[0]] = 1;
for (int i = 1; i <= m; ++i) {
while (L > node[i].l)
--L, add(L - 1);
while (R < node[i].r)
++R, add(R);
while (L < node[i].l)
sub(L - 1), ++L;
while (R > node[i].r)
sub(R), --R;
ans[node[i].id] = curans;
}
for (int i = 1; i <= m; ++i)
printf("%lld
", ans[i]);
}
}
https://codeforces.com/contest/86/problem/D
https://codeforces.com/contest/1288/problem/E
https://codeforces.com/contest/877/problem/F
带修改莫队:增加一维时间T,代表在进行了T次修改之后才进行该次询问。
树上莫队:按树的欧拉序(进入和退出某个节点都记录)一维化成一个序列,fst[x],lst[x],查询[x,y]路径的信息(不妨设fst[x]<fst[y]),当x和y是祖先/后代关系时(fst[x]<fst[y]<lst[y]<fst[x])查询[fst[x],fst[y]]就是x和y之间的节点。否则在遍历x退出之后到进入y的过程中走过的就是[x,y]的路径[lst[x],fst[y]],当然lca(x,y)也在路径上但是不出现在上述区间内,也另外加进去。