• 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;
    }
    

     

  • 相关阅读:
    Quartz.NET-2.3.3 各种 数据库配置 类别大全
    C#获取当前路径的七种方法 【转载】
    BCB 如何拦截TAB键消息
    用union 和 struct 位域操作
    表值函数
    C#中 委托和事件的关系
    关于C++ Builder Codegurad 问题的排查。
    存储过程中使用事务的“正规”写法
    C++ 中对vector<T*> 数组的查找和排序
    BCB 中 Application->CreateForm 和 New 的一个区别
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/9221864.html
Copyright © 2020-2023  润新知