莫队算法学习笔记

莫队

  • 普通莫队

    • 这个很基础。
  • 带修莫队

  • 就在普通莫队的基础上加上时间这一维度。

  • [P1903 国家集训队] 数颜色 / 维护队列

  • 回滚莫队

    • 为什么要回滚? 因为有些信息不好撤销,比如区间众数。

    • 和普通莫队相比较,就是对于每一个块,左端点放在块的右端点处,每次向左扩展,临时记录答案,

    • 对于右端点,由于我们排序时是将一个块内的右端点从小到大排序,所以按照普通莫队的扩展就行。

    • 块间的转换直接全部清空。

    • 【模板】回滚莫队&不删除莫队

    • JOISC 2014 Day1 历史研究

  • 树上莫队

    • 首先我们得会树上分块

    • 有按大小(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!
 
 

posted @ 2023-09-09 11:28  CraneWilliams  阅读(7)  评论(0编辑  收藏  举报