莫队 —— 可持久化 + 树上 + 回滚

1、奇偶性排序 + 快速读入输出

模板题:P1972   HH的项链

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const int maxn = 1e6 + 5;
int a[maxn], cnt[maxn], belong[maxn];
int n, m, size, bnum, now, ans[maxn];
struct query {
	int l, r, id;
} q[maxn];

inline int cmp(query a, query b) {
	return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : \
	       ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
}

const int MAXSIZE=100000;
char buf[MAXSIZE],*p1=buf,*p2=buf;
#define nc p1==p2&&(p2=(p1=buf)+fread\
(buf,1,MAXSIZE,stdin),p1==p2)?EOF:*p1++
inline void read(int &x) {
	bool f=0; char ch=nc; x=0;
	while(!isdigit(ch)) {if(ch=='-')f=1;ch=nc;}
	while(isdigit(ch)) x=x*10+ch-'0',ch=nc;
	if(f) x=-x;
}
inline void print(int x) { 	
	if(x<0) putchar('-'), x=-x;
	if(x>9) print(x/10);
	putchar(x%10+'0');
}

inline void add(int pos) {
    if(!cnt[a[pos]]) ++now;
    ++cnt[a[pos]];
}
inline void del(int pos) {
    --cnt[a[pos]];
    if(!cnt[a[pos]]) --now;
}

int main() {
	read(n);
	size = sqrt(n);
	bnum = ceil(1.0 * n / size);
	for(int i=1; i<=bnum; ++i)
		for(int j=(i-1)*size+1; j<=i*size; ++j) 
			belong[j] = i;
	for(int i=1; i<=n; ++i) read(a[i]);
	read(m);
	for(int i=1; i<=m; ++i) {
		read(q[i].l), read(q[i].r);
		q[i].id = i;
	}
	sort(q+1, q+m+1, cmp);
	
	int l = 1, r = 0;
	for(int i=1; i<=m; ++i) {
		int ql = q[i].l, qr = q[i].r;
		while(l < ql) del(l++);
		while(l > ql) add(--l);
		while(r < qr) add(++r);
		while(r > qr) del(r--);
		ans[q[i].id] = now;
	}
	for(int i=1; i<=m; ++i)
		print(ans[i]), putchar('\n');
}

2、带修改莫队

模板题:P1903   数颜色

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
const int maxc = 1e6 + 5;
int a[maxn], cnt[maxc], ans[maxn], belong[maxn];
int cntq, cntc, n, m, size, bnum, now;

struct query {
	int l, r, time, id;
} q[maxn];
struct modify {
	int pos, color, last;
} c[maxn];

inline int cmp(query a, query b) {
	return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] :\
	 ((belong[a.r] ^ belong[b.r]) ? belong[a.r] < belong[b.r] : a.time < b.time);
}

inline int read() {
	int res = 0;
	char ch=getchar();
	while(ch>'9'|| ch<'0') ch=getchar();
	while((ch>='0' && ch<='9')) res = (res<<1)+(res<<3)+ch-48, ch=getchar();
	return res;
}
inline void add(const int x){
	if(++cnt[x] == 1) ++now;
}

inline void del(int x){
	if(--cnt[x] == 0) --now;
}

int main() {
	n = read(), m = read();
	size = pow(n, 2.0 / 3.0);
	bnum = ceil((double)n / size);
	for(int i=1; i<=bnum; ++i)
		for(int j=(i-1)*size+1; j<=i*size; ++j) 
			belong[j] = i;
	for(int i=1; i<=n; ++i)
		a[i] = read();
	for(int i=1; i<=m; ++i) {
		char opt[100];
		scanf("%s", opt);
		if(opt[0] == 'Q') {
			q[++cntq].l = read();
			q[cntq].r = read();
			q[cntq].time = cntc;
			q[cntq].id = cntq;
		} else if(opt[0] == 'R') {
			c[++cntc].pos = read();
			c[cntc].color = read();
		}
	}
	sort(q+1, q+cntq+1, cmp);
	int l = 1, r = 0, time = 0; now = 0;
	for(int i = 1; i <= cntq; ++i) {
		int ql = q[i].l, qr = q[i].r, qt = q[i].time;
		while(l < ql) del(a[l++]);
		while(l > ql) add(a[--l]);
		while(r < qr) add(a[++r]);
		while(r > qr) del(a[r--]);
		while(time < qt) {
			++time;
			if(ql <= c[time].pos && c[time].pos <= qr) 
				del(a[c[time].pos]), add(c[time].color);
			swap(a[c[time].pos], c[time].color);
		}
		while(time > qt) {
			if(ql <= c[time].pos && c[time].pos <= qr) 
				del(a[c[time].pos]), add(c[time].color);
			swap(a[c[time].pos], c[time].color);
			--time;
		}
		ans[q[i].id] = now;
	}
	
	for(int i = 1; i <= cntq; ++i) printf("%d\n", ans[i]);
}

3、树上莫队

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 200200
int read() {
	int res = 0;
	char ch=getchar();
	while(ch>'9'|| ch<'0') ch=getchar();
	while((ch>='0' && ch<='9')) res = (res<<1)+(res<<3)+ch-48, ch=getchar();
	return res;
}
int ncnt, l = 1, r, now, size, bnum; //莫队相关
int aa[maxn], cnt[maxn], first[maxn], last[maxn], ans[maxn], belong[maxn], inp[maxn], vis[maxn];
int ord[maxn], val[maxn], head[maxn], depth[maxn], fa[maxn][30], ecnt;
int n, m;
struct edge {
	int to, next;
} e[maxn];

void adde(int u, int v) {
	e[++ecnt] = (edge) {
		v, head[u]
	};
	head[u] = ecnt;
	e[++ecnt] = (edge) {
		u, head[v]
	};
	head[v] = ecnt;
}
void dfs(int x) {
	ord[++ncnt] = x;
	first[x] = ncnt;
	for(int k=head[x]; k; k=e[k].next) {
		int to = e[k].to;
		if(to == fa[x][0]) continue;
		depth[to] = depth[x] + 1;
		fa[to][0] = x;
		for(int i=1; (1<<i)<=depth[to]; ++i) fa[to][i] = fa[fa[to][i-1]][i-1];
		dfs(to);
	}
	ord[++ncnt] = x;
	last[x] = ncnt;
}
int getlca(int u, int v) {
	if(depth[u] < depth[v]) swap(u, v);
	for(int i=20; i+1; --i)
		if(depth[u] - (1 << i) >= depth[v]) u = fa[u][i];
	if(u == v) return u;
	for(int i=20; i+1; --i)
		if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}
struct query {
	int l, r, lca, id;
} q[maxn];
int cmp(query a, query b) {
	return (belong[a.l] ^ belong[b.l]) ? (belong[a.l] < belong[b.l])\
	       : ((belong[a.l] & 1) ? a.r < b.r : a.r > b.r);
}
void work(int pos) {
	vis[pos] ? now -= !--cnt[val[pos]] : now += !cnt[val[pos]]++;
	vis[pos] ^= 1;
}

int main() {
	n = read();
	m = read();
	for(int i=1; i<=n; ++i)
		val[i] = inp[i] = read();
	sort(inp+1, inp+n+1);
	int tot = unique(inp+1, inp+n+1) - inp - 1;
	for(int i=1; i<=n; ++i)
		val[i] = lower_bound(inp+1, inp+tot+1, val[i]) - inp;
	for(int i=1; i<n; ++i) adde(read(), read());
	depth[1] = 1;
	dfs(1);
	
	size = sqrt(ncnt), bnum = ceil((double) ncnt / size);
	for(int i=1; i<=bnum; ++i)
		for(int j=size*(i-1)+1; j<=i*size; ++j) 
			belong[j] = i;
			
	for(int i=1; i<=m; ++i) {
		int L = read(), R = read(), lca = getlca(L, R);
		if(first[L] > first[R]) swap(L, R);
		if(L == lca) {
			q[i].l = first[L];
			q[i].r = first[R];
		} else {
			q[i].l = last[L];
			q[i].r = first[R];
			q[i].lca = lca;
		}
		q[i].id = i;
	}
	sort(q+1, q+m+1, cmp);
	for(int i=1; i<=m; ++i) {
		int ql = q[i].l, qr = q[i].r, lca = q[i].lca;
		while(l < ql) work(ord[l++]);
		while(l > ql) work(ord[--l]);
		while(r < qr) work(ord[++r]);
		while(r > qr) work(ord[r--]);
		if(lca) work(lca);
		ans[q[i].id] = now;
		if(lca) work(lca);
	}
	
	for(int i=1; i<=m; ++i) 
		printf("%d\n", ans[i]);
}

4、回滚莫队

(暂时感觉用不着,待填坑…)


参考博客:莫队算法——从入门到黑题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值