• HDU 6271 Master of Connected Component(2017 CCPC 杭州 H题,树分块 + 并查集的撤销)


    题目链接  2017 CCPC Hangzhou Problem H

    思路:对树进行分块。把第一棵树分成$sqrt{n}$块,第二棵树也分成$sqrt{n}$块。

         分块的时候满足每个块是一个连通块,那么每个块就有一个共同的祖先。

              把询问按照第一个点被第一棵树的哪个祖先管辖和第二个点被第二棵树的哪个祖先管辖,分成$n$类。

              每一类询问一起处理,处理完后用可撤销并查集恢复到之前的状态。

              每一类询问之间依次转移,每次转移,移动次数不会超过$sqrt{n}$次。

              最后总时间复杂度$O(n^{1.5}logn)$

    #include <map>
    #include <set>
    #include <cmath>
    #include <ctime>
    #include <queue>
    #include <stack>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cassert>
    #include <cstring>
    #include <fstream>
    #include <sstream>
    #include <utility>
    #include <iostream>
    #include <algorithm>
    #include <unordered_map>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    #define MP		make_pair
    #define fi		first
    #define se		second
    
    
    typedef long long LL;
    
    const int N = 1e4 + 10;
    const int M = 505;
    
    struct node{
    	int x, y, id;
    } s[N << 5];
    
    int T;
    int n, m;
    int top;
    int fa1[N], fa2[N], bs;
    int id1[N], id2[N];
    int re[M][M];
    int father[N], sz[N];
    int ans;
    int ret[N];
    int ux[N], uy[N], vx[N], vy[N];
    
    vector <int>  v[N], v1, v2;
    vector <node> q[M][M];
    
    void dfs1(int x, int fa, int dep){
    	fa1[x] = fa;
    	id1[x] = -1;
    	if (dep % bs == 0){
    		id1[x] = v1.size();
    		v1.push_back(x);
    	}
    
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		dfs1(u, x, dep + 1);
    	}
    }
    
    void dfs2(int x, int fa, int dep){
    	fa2[x] = fa;
    	id2[x] = -1;
    
    	if (dep % bs == 0){
    		id2[x] = v2.size();
    		v2.push_back(x);
    	}
    
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		dfs2(u, x, dep + 1);
    	}
    }
    
    void merge_(int x, int y){
    	while (x != father[x]) x = father[x];
    	while (y != father[y]) y = father[y];
    
    	if (x == y) return;
    
    	if (sz[x] > sz[y]) swap(x, y);
    
    	s[++top]  = {x, y};
    	father[x] = y;
    
    	--ans;
    	sz[y] += sz[x];
    }
    
    
    void recover(int x, int y){
    	while (top > re[id1[x]][id2[y]]){
    		auto u = s[top--];
    		++ans;
    		father[u.x] = u.x;
    		father[u.y] = u.y;
    		sz[u.y] -= sz[u.x];
    	}
    }
    
    void commit(int x, int y){
    	int tx = x, ty = y;
    	for (; id1[tx] == -1; tx = fa1[tx]){}
    	for (; id2[ty] == -1; ty = fa2[ty]){}
    
    	recover(tx, ty);
    
    	while (x != tx){
    		merge_(ux[x], vx[x]);
    		x = fa1[x];
    	}
    
    	while (y != ty){
    		merge_(uy[y], vy[y]);
    		y = fa2[y];
    	}
    }
    
    
    int main(){
    
    	scanf("%d", &T);
    	while (T--){
    		scanf("%d%d", &n, &m);
    		rep(i, 1, n) scanf("%d%d", ux + i, vx + i);
    			
    		bs = sqrt(n);
    
    		rep(i, 0, n + 1) v[i].clear();
    		
    		rep(i, 2, n){
    			int x, y;
    			scanf("%d%d", &x, &y);
    			v[x].push_back(y);
    			v[y].push_back(x);
    		}
    
    		v1.clear();
    		dfs1(1, 0, 0);
    		
    		rep(i, 0, n + 1) v[i].clear();
    		rep(i, 1, n) scanf("%d%d", uy + i, vy + i);
    		
    		rep(i, 2, n){
    			int x, y;
    			scanf("%d%d", &x, &y);
    			v[x].push_back(y);
    			v[y].push_back(x);
    		}
    
    		v2.clear();
    		dfs2(1, 0, 0);
    
    
    		rep(i, 1, n){
    			int u, v, x, y;
    			u = v = i;
    			x = u, y = v;
    
    			for (; id1[x] == -1; x = fa1[x]){}
    			for (; id2[y] == -1; y = fa2[y]){}
    
    			q[id1[x]][id2[y]].push_back({u, v, i});
    
    		}
    
    		rep(i, 1, m) father[i] = i, sz[i] = 1;
    
    		ans = m;
    
    		merge_(ux[1], vx[1]);
    		merge_(uy[1], vy[1]);
    
    
    		re[0][0] = (top = 0);
    		
    
    		for (auto x : v1){
    			for (auto y : v2){
    				if (x == 1 && y == 1){
    					merge_(ux[x], vx[x]);
    					merge_(uy[y], vy[y]);
    				}
    
    				else if (y == 1){
    					commit(fa1[x], y);
    					merge_(ux[x], vx[x]);
    				}
    
    				else{
    					commit(x, fa2[y]);
    					merge_(uy[y], vy[y]);
    				}
    
    				re[id1[x]][id2[y]] = top;
    
    				for (auto u : q[id1[x]][id2[y]]){
    					commit(u.x, u.y);
    					ret[u.id] = ans;
    				}
    
    				q[id1[x]][id2[y]].clear();
    			}
    		}
    
    		rep(i, 1, n) printf("%d
    ", ret[i]);	
    		
    	}
    
    	return 0;
    }
    

     

  • 相关阅读:
    谷歌浏览器插件开发Tutorial: Getting Started (Hello, World!) 教程:准备开始(你好,世界!)
    Android ViewPager多页面滑动切换以及动画效果
    4.4 我同意条款—CheckBox的isCheck属性
    4.2设计具有背景图的按钮—ImageButton的焦点及事件处理
    【文件打开】浏览打开窗口
    【原创】PE检测工具
    emu8086注册算法分析及KeyGen实现
    学破解 <一> PE格式之MSDOS MZ header
    学破解 <二> PE格式之IMAGE_NT_HEADERS
    反虚拟机程序测试
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/9221864.html
Copyright © 2020-2023  润新知