zoukankan      html  css  js  c++  java
  • BZOJ3673 可持久化并查集 by zky <可持久化数组+主席树>

    可持久化并查集 by zky

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

    Sample Input
    5 6
    1 1 2
    3 1 2
    2 0
    3 1 2
    2 1
    3 1 2
    Sample Output
    1
    0
    1
    Hint
    0 < n,m <= 2*10^4

    标签:主席树维护可持久化数组

    本题的做法其实和并查集没太大关联。
    如果是撤销,那可以用不加路径压缩的并查集完成,但是如果回到某时间,则不太好写。
    这时,我们发现并查集这个东西构造其实很简单,只需要一个fa数组就行了。所以我们自然可以想到直接用一个二维数组存储每个时间的fa数组,即用增加的一维表示时间。
    但是,n、m是2e4级别,所以肯定会MLE,这里我们就需要用到主席树,把fa数组可持久化。这里需要注意我们不能用路径压缩优化,因为我们需要回到前面的状态,为了让它跑得更快,我们可以用按秩合并优化。
    最后附上AC代码:

    #include <iostream>
    #include <cstdio>
    #define MAX_N 20000
    using namespace std;
    int n, m, cnt, now, root[MAX_N*10+5];
    struct node {int fa, dep, ls, rs;} tr[MAX_N*100+5];
    void build(int v, int l, int r) {
    	if (l == r) {tr[v].fa = l;	return;}
    	int mid = l+r>>1;
    	tr[v].ls = ++cnt, tr[v].rs = ++cnt;
    	build(tr[v].ls, l, mid);
    	build(tr[v].rs, mid+1, r);
    }
    void modifyfa(int v, int o, int s, int t, int pos, int x) {
    	tr[v] = tr[o];
    	if (s == t)	{tr[v].fa = x;	return;}
    	int mid = s+t>>1;
    	if (pos <= mid)	modifyfa(tr[v].ls = ++cnt, tr[o].ls, s, mid, pos, x);
    	else	modifyfa(tr[v].rs = ++cnt, tr[o].rs, mid+1, t, pos, x);
    }
    void modifydep(int v, int s, int t, int pos) {
    	if (s == t)	{tr[v].dep++;	return;}
    	int mid = s+t>>1;
    	if (pos <= mid)	modifydep(tr[v].ls, s, mid, pos);
    	else	modifydep(tr[v].rs, mid+1, t, pos);
    }
    int find(int v, int s, int t, int pos) {
    	if (s == t)	return v;
    	int mid = s+t>>1;
    	if (pos <= mid)	return find(tr[v].ls, s, mid, pos);
    	else	return find(tr[v].rs, mid+1, t, pos);
    }
    int getf(int r, int x) {
    	int pos = find(r, 1, n, x);
    	if (tr[pos].fa != x)	return getf(r, tr[pos].fa);
    	return pos;
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	cnt = 0, root[0] = ++cnt;
    	build(root[0], 1, n);
    	for (int now = 1; now <= m; now++) {
    		int opt;
    		scanf("%d", &opt);
    		if (opt == 1) {
    			root[now] = root[now-1];
    			int a, b;
    			scanf("%d%d", &a, &b);
    			int posa = getf(root[now], a), posb = getf(root[now], b);
    			if (tr[posa].fa == tr[posb].fa)	continue;
    			if (tr[posa].dep > tr[posb].dep)	swap(posa, posb);
    			root[now] = ++cnt;
    			modifyfa(root[now], root[now-1], 1, n, tr[posa].fa, tr[posb].fa);
    			if (tr[posa].dep == tr[posb].dep)	modifydep(root[now], 1, n, tr[posb].fa);
    		}
    		if (opt == 2) {
    			int k;
    			scanf("%d", &k);
    			root[now] = root[k];
    		}
    		if (opt == 3) {
    			root[now] = root[now-1];
    			int a, b;
    			scanf("%d%d", &a, &b);
    			if (tr[getf(root[now], a)].fa == tr[getf(root[now], b)].fa)	printf("1
    ");
    			else	printf("0
    ");
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    swift 资料
    CI cookie 存放数组
    CI框架中 日志输出方法log_message()只允许输出字符串解决方案
    CI框架整合微信公共平台接口
    php中的 file_get_contents(‘php://input’)
    CI 框架购物车问题
    JQ 报表插件 jquery.jqplot 使用
    微信开发调试工具
    常用开源库
    字符集更改步骤,mysql乱码
  • 原文地址:https://www.cnblogs.com/AzraelDeath/p/7561726.html
Copyright © 2011-2022 走看看