zoukankan      html  css  js  c++  java
  • 【bzoj3674】 可持久化并查集加强版

    http://www.lydsy.com/JudgeOnline/problem.php?id=3674 (题目链接)

    题意

      维护并查集3个操作:合并;回到完成第k个操作后的状态;查询。

    Solution

      其实就是用主席树的叶子节点维护并查集的可持久化数组fa[]。

    细节

      终于认识到了按秩合并的强大,单纯写个路径压缩Re飞,写了路径压缩+按秩合并比单纯的按秩合并没快多少→_→

    代码

    // bzoj3674
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=200010,maxm=10000010;
    struct tree {int ls,rs;}tr[maxm];
    int fa[maxm],deep[maxm],rt[maxn],n,m,sz;
    
    void build(int &k,int l,int r) {
    	if (!k) k=++sz;
    	if (l==r) {fa[k]=l;return;}
    	int mid=(l+r)>>1;
    	build(tr[k].ls,l,mid);
    	build(tr[k].rs,mid+1,r);
    }
    void update(int &k1,int k2,int l,int r,int x,int val) {
    	k1=++sz;tr[k1]=tr[k2];
    	int mid=(l+r)>>1;
    	if (l==r) {fa[k1]=val,deep[k1]=deep[k2];return;}
    	if (x<=mid) update(tr[k1].ls,tr[k2].ls,l,mid,x,val);
    	else update(tr[k1].rs,tr[k2].rs,mid+1,r,x,val);
    }
    void add(int k,int l,int r,int x) {
    	if (l==r) {deep[k]++;return;}
    	int mid=(l+r)>>1;
    	if (x<=mid) add(tr[k].ls,l,mid,x);
    	else add(tr[k].rs,mid+1,r,x);
    }
    int query(int k,int l,int r,int x) {
    	int mid=(l+r)>>1;
    	if (l==r) return k;
    	if (x<=mid) return query(tr[k].ls,l,mid,x);
    	else return query(tr[k].rs,mid+1,r,x);
    }
    int find(int k,int x) {
    	int p=query(k,1,n,x);
    	if (x==fa[p]) return p;
    	int t=find(k,fa[p]);
    	update(k,k,1,n,fa[p],fa[t]);
    	return t;
    }
    int main() {
    	scanf("%d%d",&n,&m);
    	build(rt[0],1,n);
    	int ans=0;
    	for (int op,a,b,i=1;i<=m;i++) {
    		scanf("%d",&op);
    		if (op==1) {
    			rt[i]=rt[i-1];
    			scanf("%d%d",&a,&b);a^=ans,b^=ans;
    			int r1=find(rt[i],a),r2=find(rt[i],b);
    			if (fa[r1]==fa[r2]) continue;
    			//if (deep[r1]>deep[r2]) swap(r1,r2);
    			update(rt[i],rt[i-1],1,n,fa[r1],fa[r2]);
    			//if (deep[r1]==deep[r2]) add(rt[i],1,n,fa[r2]);
    		}
    		if (op==2) {scanf("%d",&a);a^=ans;rt[i]=rt[a];}
    		if (op==3) {
    			rt[i]=rt[i-1];
    			scanf("%d%d",&a,&b);
    			a^=ans,b^=ans;
    			int r1=find(rt[i],a),r2=find(rt[i],b);
    			ans=fa[r1]==fa[r2] ? 1 : 0;
    			printf("%d
    ",ans);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    redis的两种备份方式
    Vue—事件修饰符
    css3实现颤动的动画
    初学者可能不知道的vue技巧
    使用slot-scope复制vue中slot内容
    pre-commit钩子,代码质量检查
    爬虫可视化点选配置工具之获取鼠标点选元素
    Vue源码探究-事件系统
    使用electron实现百度网盘悬浮窗口功能!
    electron实现qq快捷登录!
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6036495.html
Copyright © 2011-2022 走看看