# 胡小兔的良心莫队教程：莫队、带修改莫队、树上莫队

### 可离线、无修改的莫队

sort(q + 1, q + m + 1); //将询问排序
int ql = 1, qr = 0; //初始区间是一个空区间
for(int i = 1; i <= m; i++){
while(pl < q[i].l) del(a[pl++]); //
while(pr > q[i].r) del(a[pr--]);
ans[q[i].id] = sum;
}


——可是，这样做的复杂度是什么？

while(pl < q[i].l) del(a[pl++]);
while(pr > q[i].r) del(a[pr--]);
ans[q[i].id] = sum;


BZOJ 1878 HH的项链我的AC代码：

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 50005, M = 200005, B = 233;
int n, m, a[N], sum, ans[M], cnt[1000005];
#define bel(x) ((x - 1) / B + 1)
struct query {
int id, l, r;
bool operator < (const query &b) const{
return bel(l) == bel(b.l) ? r < b.r : l < b.l;
}
} q[M];
if(!cnt[x]) sum++;
cnt[x]++;
}
void del(int x){
cnt[x]--;
if(!cnt[x]) sum--;
}
int main(){
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1; i <= m; i++)
sort(q + 1, q + m + 1);
int pl = 1, pr = 0;
for(int i = 1; i <= m; i++){
while(pl < q[i].l) del(a[pl++]);
while(pr > q[i].r) del(a[pr--]);
ans[q[i].id] = sum;
}
for(int i = 1; i <= m; i++)
write(ans[i]), enter;
return 0;
}


## 可以单点修改的莫队

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
const int N = 10005, M = 1000005, B = 464;
int n, m, pl = 1, pr = 0, cur, res, ans[N], a[N], cnt[M];
int idxC, idxQ, tim[N], pos[N], val[N], pre[N];
#define bel(x) (((x) - 1) / B + 1)
struct query {
int id, tim, l, r;
bool operator < (const query &b) const {
if(bel(l) != bel(b.l)) return l < b.l;
if(bel(r) != bel(b.r)) return r < b.r;
return id < b.id;
}
} q[N];
if(pos[cur] >= pl && pos[cur] <= pr){
cnt[a[pos[cur]]]--;
if(!cnt[a[pos[cur]]]) res--;
}
pre[cur] = a[pos[cur]];
a[pos[cur]] = val[cur];
if(pos[cur] >= pl && pos[cur] <= pr){
if(!cnt[a[pos[cur]]]) res++;
cnt[a[pos[cur]]]++;
}
}
void change_del(int cur){
if(pos[cur] >= pl && pos[cur] <= pr){
cnt[a[pos[cur]]]--;
if(!cnt[a[pos[cur]]]) res--;
}
a[pos[cur]] = pre[cur];
if(pos[cur] >= pl && pos[cur] <= pr){
if(!cnt[a[pos[cur]]]) res++;
cnt[a[pos[cur]]]++;
}
}
void change(int now){
while(cur < idxC && tim[cur + 1] <= now) change_add(++cur);
while(cur && tim[cur] > now) change_del(cur--);
}
if(!cnt[a[p]]) res++;
cnt[a[p]]++;
}
void del(int p){
cnt[a[p]]--;
if(!cnt[a[p]]) res--;
}
bool isQ(){
char op[2];
scanf("%s", op);
return op[0] == 'Q';
}
int main(){
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1; i <= m; i++){
}
sort(q + 1, q + idxQ + 1);
for(int i = 1; i <= idxQ; i++){
change(q[i].tim);
while(pl < q[i].l) del(pl++);
while(pr > q[i].r) del(pr--);
ans[q[i].id] = res;
}
for(int i = 1; i <= idxQ; i++)
write(ans[i]), enter;
return 0;
}


## 树上莫队

T(v, u) = S(root, v) xor S(root, u)（摘者注：显然等式右侧是u到v的路径上除lca以外的点）

T(curV, curU) = S(root, curV) xor S(root, curU)
T(targetV, curU) = S(root, targetV) xor S(root, curU)

T(curV, curU) xor T(targetV, curU)= (S(root, curV) xor S(root, curU)) xor (S(root, targetV) xor S(root, curU))

T(curV, curU) xor T(targetV, curU)= S(root, curV) xor S(root, targetV)

T(targetV, curU)= T(curV, curU) xor S(root, curV) xor S(root, targetV)

T(targetV, curU)= T(curV, curU) xor T(curV, targetV)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
template <class T>
char c;
bool op = 0;
while(c = getchar(), c < '0' || c > '9')
if(c == '-') op = 1;
x = c - '0';
while(c = getchar(), c >= '0' && c <= '9')
x = x * 10 + c - '0';
if(op) x = -x;
}
template <class T>
void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x >= 10) write(x / 10);
putchar('0' + x % 10);
}
#define space putchar(' ')
#define enter putchar('\n')

const int N = 200005, B = 2005;
int n, maxcol, m, bel[N], idx, stk[N], top, pu, pv, cur;
int cntQ, cntC, tim[N], pos[N], newx[N], col[N], pre[N], cnt[N];
ll val[N], wei[N], res, ans[N];
int fa[N], lg[2*N], dep[N], seq[2*N], seq_cnt, seq_pos[N], mi[2*N][20];
bool vis[N];
struct query {
int id, tim, u, v;
bool operator < (const query &b) const {
if(bel[u] != bel[b.u]) return bel[u] < bel[b.u];
if(bel[v] != bel[b.v]) return bel[v] < bel[b.v];
return tim < b.tim;
}
} q[N];

go[++ecnt] = v;
}
void dfs(int u, int pre){
dep[u] = dep[pre] + 1, fa[u] = pre;
seq[++seq_cnt] = u, seq_pos[u] = seq_cnt;
int st = top;
for(int e = adj[u], v; e; e = nxt[e])
if(v = go[e], v != pre){
dfs(v, u);
seq[++seq_cnt] = u;
if(top - st > B){
idx++;
while(top > st) bel[stk[top--]] = idx;
}
}
stk[++top] = u;
}
int Min(int a, int b){
return dep[a] < dep[b] ? a : b;
}
void lca_init(){
for(int i = 1, j = 0; i <= seq_cnt; i++)
lg[i] = i == (1 << (j + 1)) ? ++j : j;
for(int i = 1; i <= seq_cnt; i++) mi[i][0] = seq[i];
for(int j = 1; (1 << j) <= seq_cnt; j++)
for(int i = 1; i + (1 << j) - 1 <= seq_cnt; i++)
mi[i][j] = Min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]);
}
int lca(int u, int v){
u = seq_pos[u], v = seq_pos[v];
if(u > v) swap(u, v);
int j = lg[v - u + 1];
return Min(mi[u][j], mi[v - (1 << j) + 1][j]);
}
void reverse(int u){
if(vis[u]) res -= wei[cnt[col[u]]] * val[col[u]], cnt[col[u]]--;
else cnt[col[u]]++, res += wei[cnt[col[u]]] * val[col[u]];
vis[u] ^= 1;
}
void move(int u, int v){
int w = lca(u, v);
while(u != w) reverse(u), u = fa[u];
while(v != w) reverse(v), v = fa[v];
}
bool flag = 0;
if(vis[pos[cur]]) flag = 1, reverse(pos[cur]);
pre[cur] = col[pos[cur]];
col[pos[cur]] = newx[cur];
if(flag) reverse(pos[cur]);
}
void travel_back(){
bool flag = 0;
if(vis[pos[cur]]) flag = 1, reverse(pos[cur]);
col[pos[cur]] = pre[cur];
if(flag) reverse(pos[cur]);
}
void time_travel(int tar){
while(cur < cntC && tim[cur + 1] <= tar) cur++, travel_ahead();
while(cur && tim[cur] > tar) travel_back(), cur--;
}

int main(){
for(int i = 1; i <= maxcol; i++) read(val[i]);
for(int i = 1; i <= n; i++) read(wei[i]);
for(int i = 1, u, v; i < n; i++)
for(int i = 1; i <= n; i++) read(col[i]);
for(int i = 1, op; i <= m; i++){
}
dfs(1, 0);
lca_init();
while(top) bel[stk[top--]] = idx;
sort(q + 1, q + cntQ + 1);
pu = pv = 1;
for(int i = 1; i <= cntQ; i++){
time_travel(q[i].tim);
move(pu, q[i].u), pu = q[i].u;
move(pv, q[i].v), pv = q[i].v;
reverse(lca(pu, pv));
ans[q[i].id] = res;
reverse(lca(pu, pv));
}
for(int i = 1; i <= cntQ; i++)
write(ans[i]), enter;
return 0;
}


posted @ 2017-12-01 14:45  胡小兔  阅读(5265)  评论(8编辑  收藏  举报