zoukankan      html  css  js  c++  java
  • BZOJ4668: 冷战 [并查集 按秩合并]

    BZOJ4668: 冷战

    题意:

    给定 n 个点的图。动态的往图中加边,并且询问某两个点最早什
    么时候联通,强制在线。


    还可以这样乱搞

    并查集按秩合并的好处:

    1. 深度不会超过(O(log n))
    2. 树的结构保持较稳定 -> 虽说连边的时候依旧是祖先来连边,但连边不会改变原来的结构,并且(u,v)路径上会经过新连的边

    于是就可以乱搞了

    维护一个按秩合并的并查集,给连边操作加时间戳,查询的时候暴力求路径上时间戳最大值

    PS:暴力lca也是需要deep

    PS2:按秩合并是看高度的吧,为什么我的好慢???人傻自带大常数???并且改成启发式合并我的就T掉了

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    const int N = 5e5+5;
    
    int n, m, fa[N], val[N], he[N], deep[N], tim, ans;
    int find(int x) {
    	if(x == fa[x]) return x;
    	else {
    		int f = find(fa[x]);
    		deep[x] = deep[fa[x]] + 1;
    		return f;
    	}
    }
    void Union(int x, int y) {
    	tim++;
    	x = find(x); y = find(y);
    	if(x == y) return;
    	if(he[x] < he[y]) swap(x, y);
    	fa[y] = x;
    	val[y] = tim;
    	he[x] = max(he[x], he[y]+1);
    }
    void Find(int x, int y) {
    	int fx = find(x), fy = find(y);
    	ans = 0;
    	if(fx != fy) cout << ans << '
    ';
    	else {
    		while(x != y) {
    			if(deep[x] < deep[y]) swap(x, y);
    			ans = max(ans, val[x]); x = fa[x];
    		}
    		cout << ans << '
    ';
    	}
    }
    int main() {
    	freopen("in", "r", stdin);
    	ios::sync_with_stdio(false); cin.tie(); cout.tie();
    	cin >> n >> m;
    	for(int i=1; i<=n; i++) fa[i] = i;
    	for(int i=1; i<=m; i++) {
    		int c, x, y;
    		cin >> c >> x >> y;
    		x ^= ans; y ^= ans; //printf("hi %d %d %d
    ", c, x, y);
    		if(c == 0) Union(x, y);
    		else Find(x, y);
    	}
    }
    
    
  • 相关阅读:
    如何解决"应用程序无法启动,因为应用程序的并行配置不正确"问题
    C/C++时间函数使用方法
    vim: C++文件之间快速切换(含视频)
    HOWTO install commonlisp on ubuntu
    TagSoup home page
    Quicklisp beta
    What is Lispbox?
    猫人女王
    Lisp in a box 安装指南 JAAN的专栏 博客频道 CSDN.NET
    Ubuntu 12.04 改造指南 | Ubuntusoft
  • 原文地址:https://www.cnblogs.com/candy99/p/9288086.html
Copyright © 2011-2022 走看看