莫队算法学习笔记
莫队
-
普通莫队
- 这个很基础。
-
带修莫队
-
就在普通莫队的基础上加上时间这一维度。
-
[P1903 国家集训队] 数颜色 / 维护队列
-
回滚莫队
-
为什么要回滚? 因为有些信息不好撤销,比如区间众数。
-
和普通莫队相比较,就是对于每一个块,左端点放在块的右端点处,每次向左扩展,临时记录答案,
-
对于右端点,由于我们排序时是将一个块内的右端点从小到大排序,所以按照普通莫队的扩展就行。
-
块间的转换直接全部清空。
-
-
树上莫队
-
首先我们得会树上分块
-
有按大小(size),深度(dep)不同的分块方式, 取决于题目。
-
按 size 分块的思想可以参考 [P2325 SCOI2005] 王室联邦
-
简单来讲,就是优先填下面的,满了阈值就更新, 随后上面剩下的和根一组。
-
拿这题举例[P4074 WC2013] 糖果公园
-
树分块之后, 我们类似在树上游走做修改莫队,注意lca处可能会出现问题,所以我们每次临时将lca点上,最后再撤销。
-
-
附录(树size分块代码)
int st[maxn], tp; int bel[maxn]; vector<int> G[maxn]; int pro[maxn]; int B, cnt; void dfs(int x, int f) { int cur = tp; for (auto i : G[x]) { if (i != f) { dfs(i, x); if (tp - B >= cur) { cnt++; pro[cnt] = x; while(tp > cur) { bel[st[tp--]] = cnt; } } } } st[++tp] = x; } // main if (!cnt) cnt++; while(tp) { bel[st[tp--]] = cnt; } pro[cnt] = 1;
-
[P4074 [WC2013] 糖果公园] 代码
#include <bits/stdc++.h>
#define for_(i,a,b) for (int i = (a); i < (b); i++)
#define rep_(i,a,b) for (int i = (a); i <= (b); i++)
#define per_(i,a,b) for (int i = (a); i >= (b); i--)
#define pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define ll long long
#define sz(a) (int)a.size()
#define all(v) v.begin(), v.end()
#define clr(x) memset(x, 0, sizeof(x))
#define wls(v) sort(all(v)); v.erase(unique(all(v)), v.end());
#define ull unsigned long long
#define pb push_back
#define D(x) cerr << #x << '=' << x << endl
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"]=";rep_(_x,(L),(R))cerr<<a[_x]<<" "; cerr<<endl;
#ifdef LOCAL
#define line cout << "--------------------------------" << endl;
#define CE cout << endl;
#define CO cout << "OK" << endl;
#endif
#define endl '\n'
#define int ll
using namespace std;
bool be;clock_t startTime;
double getCurrentTime() {
return (double)(clock() - startTime) / CLOCKS_PER_SEC;
}
const int maxn = 2e5 + 10, mod = 998244353;// mod = 1949777;
const double EPS = 1e-3;
template <typename Type>
void add(Type &x, Type y, Type Md = mod) {
x += y; while(x >= Md) x -= Md;
while(x < 0) x += Md;
}
int n, m;
int a[maxn], v[maxn], w[maxn], ra[maxn];
bool ed;
void solve() {
}
int B = 2000;
struct node{
int l, r, t;
int id;
}b[maxn];
struct Cnode{
int x, y, prx, t;
}c[maxn];
int q;
// ----------------------------------
vector<int> G[maxn];
int fa[maxn], son[maxn], sz[maxn], dep[maxn];
int st[maxn], top, bel[maxn], cnt;
void dfs1(int x, int f) {
sz[x] = 1, fa[x] = f, dep[x] = dep[f] + 1;
int cur = top;
for(auto i : G[x]) {
if (i != f) {
dfs1(i, x);
sz[x] += sz[i];
if (sz[i] > sz[son[x]]) son[x] = i;
if (top - cur >= B) {
cnt++;
while(top > cur) {
bel[st[top--]] = cnt;
}
}
}
}
st[++top] = x;
return;
}
int tp[maxn];
void dfs2(int x, int fp) {
tp[x] = fp;
if (son[x]) {
dfs2(son[x], fp);
}
for (auto i : G[x]) {
if (!tp[i]) assert(i != fa[x] && i != son[x]);
if (i != fa[x] && i != son[x]) {
dfs2(i, i);
}
}
}
int lca(int x, int y) {
while(tp[x] != tp[y]) {
if (dep[tp[x]] < dep[tp[y]]) swap(x, y);
x = fa[tp[x]];
}
if (dep[x] > dep[y]) return y;
else return x;
}
bool cmp(node &x, node &y) {
if (bel[x.l] != bel[y.l]) return bel[x.l] < bel[y.l];
else if (bel[x.r] != bel[y.r]) return bel[x.r] < bel[y.r];
else return x.t < y.t;
}
//------------------------------
int vis[maxn];
int occurence[maxn];
int ans = 0, Ans[maxn];
void upd(int x) {
if (vis[x]) {
ans -= w[occurence[a[x]]] * v[a[x]];
occurence[a[x]]--;
} else {
occurence[a[x]]++;
ans += w[occurence[a[x]]] * v[a[x]];
}
vis[x] ^= 1;
}
void move(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
while(dep[x] != dep[y]) upd(x), x = fa[x];
while(x != y) upd(x), x = fa[x], upd(y), y = fa[y];
return;
}
void chg(int x, int y) {
int flag = vis[x];
if (flag) upd(x);
a[x] = y;
if (flag) upd(x);
}
signed main() {
#ifdef LOCAL
freopen("w.in", "r", stdin);
// freopen("w.out", "w", stdout);
startTime = clock();
time_t now_time = time(NULL); tm* TuT = localtime(&now_time); cout << asctime(TuT); cout << "CodeBegin:_______________________" << endl;
cerr << "Memory footprint:" << ((&be - &ed) >> 20) <<"MB"<< endl;
line;
#endif
// freopen("park.in", "r", stdin);
// freopen("park.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
// int tt; cin >> tt; while(tt--) solve();
cin >> n >> m >> q;
rep_(i, 1, m) {
cin >> v[i];
}
rep_(i, 1, n) {
cin >> w[i];
}
rep_(i, 1, n - 1) {
int u, v; cin >> u >> v; G[u].pb(v); G[v].pb(u);
}
dfs1(1, 0);
if (!cnt) cnt++;
while(top) {
bel[st[top--]] = cnt;
}
dfs2(1, 1);
rep_(i, 1, n) {
cin >> a[i];
ra[i] = a[i];
}
int now_t = 0, opt, x, y;
int nq = 0;
rep_(i, 1, q) {
cin >> opt >> x >> y;
if(opt == 0) {
now_t++;
c[now_t].x = x;
c[now_t].y = y;
c[now_t].prx = ra[x];
ra[x] = y;
} else {
nq++;
b[nq].t = now_t;
b[nq].l = x, b[nq].r = y;
b[nq].id = nq;
}
}
memcpy(ra, a, sizeof(a));
q = nq;
sort(b + 1, b + q + 1, cmp);
int l = 1, r = 1, t = 0;
rep_(i, 1, nq) {
if (l != b[i].l) move(l, b[i].l), l = b[i].l;
if (r != b[i].r) move(r, b[i].r), r = b[i].r;
int f = lca(l, r);
upd(f);
while(t < b[i].t) {
t++;
chg(c[t].x, c[t].y);
}
while(t > b[i].t) {
chg(c[t].x, c[t].prx);
t--;
}
Ans[b[i].id] = ans;
upd(f);
}
rep_(i, 1, nq) {
cout << Ans[i] << '\n';
}
#ifdef LOCAL
cerr<<"\n\n-----------------------\nProgram done in "<<clock()-startTime<<" ms";
#endif
return 0;
}
//by whc
// check if over int , and open long long !!!
// check if it will RE !!! Is it only 2e5+10?? Maynot!