1. 程式人生 > >HDU 6271 Master of Connected Component(2017 CCPC 杭州 H題,樹分塊 + 並查集的撤銷)

HDU 6271 Master of Connected Component(2017 CCPC 杭州 H題,樹分塊 + 並查集的撤銷)

AS true typedef cpp define spa tac assert struct

題目鏈接 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\n", ret[i]);	
		
	}

	return 0;
}

HDU 6271 Master of Connected Component(2017 CCPC 杭州 H題,樹分塊 + 並查集的撤銷)