[BZOJ3673]可持久化并查集 by zky

[BZOJ3673]可持久化并查集 by zky

试题描述

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0

0<n,m<=2*10^4

输入

见“试题描述

输出

见“试题描述

输入示例

5 6
1 1 2
3 1 2
2 0
3 1 2
2 1
3 1 2

输出示例

1
0
1

数据规模及约定

见“试题描述

题解

用启发式合并的并查集,用主席树维护可持久化数组。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
	if(Head == Tail) {
		int l = fread(buffer, 1, BufferSize, stdin);
		Tail = (Head = buffer) + l;
	}
	return *Head++;
}
int read() {
	int x = 0, f = 1; char c = Getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
	return x * f;
}

#define maxn 20010
#define maxnode 1266666

int ToT, fa[maxnode], siz[maxnode], lc[maxnode], rc[maxnode];
void updatefa(int& y, int x, int l, int r, int p, int Fa) {
	fa[y = ++ToT] = fa[x]; siz[y] = siz[x];
	if(l == r){ fa[y] = Fa; return ; }
	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
	if(p <= mid) updatefa(lc[y], lc[x], l, mid, p, Fa);
	else updatefa(rc[y], rc[x], mid+1, r, p, Fa);
	return ;
}
void updatesiz(int& y, int x, int l, int r, int p, int Siz) {
	fa[y = ++ToT] = fa[x]; siz[y] = siz[x];
	if(l == r){ siz[y] = Siz; return ; }
	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
	if(p <= mid) updatesiz(lc[y], lc[x], l, mid, p, Siz);
	else updatesiz(rc[y], rc[x], mid+1, r, p, Siz);
}
int qfa(int o, int l, int r, int p) {
	if(!o) return 0;
	if(l == r) return fa[o];
	int mid = l + r >> 1;
	if(p <= mid) return qfa(lc[o], l, mid, p);
	return qfa(rc[o], mid+1, r, p);
}
int qsiz(int o, int l, int r, int p) {
	if(!o) return 0;
	if(l == r) return siz[o];
	int mid = l + r >> 1;
	if(p <= mid) return qsiz(lc[o], l, mid, p);
	return qsiz(rc[o], mid+1, r, p);
}

int n, rt[maxn];
int findset(int o, int x) {
	int tfa = qfa(o, 1, n, x);
	return tfa == x ? x : findset(o, tfa);
}

int main() {
//	freopen("data.in", "r", stdin);
	n = read(); int q = read();
	for(int i = 1; i <= n; i++)
		updatefa(rt[0], rt[0], 1, n, i, i), updatesiz(rt[0], rt[0], 1, n, i, 1);
	for(int i = 1; i <= q; i++) {
		int tp = read();
		if(tp == 1) {
			int a = findset(rt[i-1], read()), b = findset(rt[i-1], read());
			if(a == b){ rt[i] = rt[i-1]; continue; }
			int sa = qsiz(rt[i-1], 1, n, a), sb = qsiz(rt[i-1], 1, n, b);
			if(sa < sb) swap(a, b), swap(sa, sb);
			updatefa(rt[i], rt[i-1], 1, n, b, a);
			updatesiz(rt[i], rt[i], 1, n, a, sa + sb);
		}
		if(tp == 2) {
			int k = read();
			rt[i] = rt[k];
		}
		if(tp == 3) {
			int a = findset(rt[i-1], read()), b = findset(rt[i-1], read());
//			printf("%d %d\n", a, b);
			puts(a == b ? "1" : "0");
			rt[i] = rt[i-1];
		}
//		printf("ToT: %d\n", ToT);
	}
	
	return 0;
}

 

posted @ 2017-02-02 10:56  xjr01  阅读(183)  评论(0编辑  收藏  举报