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\n", ret[i]);	

	}

	return 0;
}

原文地址:https://www.cnblogs.com/cxhscst2/p/9221864.html

时间: 2024-11-05 00:42:25

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

[HDU6271]Master of Connected Component

[HDU6271]Master of Connected Component 题目大意: 给出两棵\(n(n\le10000)\)个结点的以\(1\)为根的树\(T_a,T_b\),和一个拥有\(m(m\le10000)\)个结点的图\(G\).\(T_a,T_b\)的每一个结点上都有一个信息,表示\(G\)中的一条边\((u_i,v_i)\).对于\(i\in[1,n]\),询问从\(T_a\)和\(T_b\)上分别取出链\(1\sim i\),将链上的信息所表示的边加入\(G\)中后,\(G

Valentine&#39;s Day Round hdu 5176 The Experience of Love [好题 带权并查集 unsigned long long]

传送门 The Experience of Love Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 221    Accepted Submission(s): 91 Problem Description A girl named Gorwin and a boy named Vivin is a couple. They arriv

2017 CCPC 杭州赛区小结 By JSB @ Reconquista

Statistics TYPE: Onsite Contest NAME: 2017 - CCPC - Hangzhou PLAT: pc^2 TIME: 2017/11/05 09:00-14:00 LOCA: Zhejiang SCI-TECH University Xiasha Campus TEAM: Reconquista[shb,lsmll,jsb] RANK: 10/190 5.26% (*Including Unofficial Teams) SOLVE: 7/12 PENALT

2017 CCPC杭州 题解

2017CCPC杭州题目PDF Problem A. Super-palindrome 题解: 给你一个字符串,每一步可以将一个字符替换为另一个字符,问你最少多少步可以使得,该字符串任意奇数子串为回文串,偶数子串为回文串. 满足上面条件一定是ababab这种形式,所以我们只要找到数量最多的两种字符用n-numa-numb得到ans1,有可能一种字符的数量过多,这时候我们只要把所有字符都变成这种字符就行了.得到n-numa,ans2; 在ans1和ans2中去最小值就是答案了: 参考代码: #in

2017 CCPC 杭州

Time: Link A 题意 分析 B 题意 分析 C 题意 分析 D 题意 分析 E 题意 分析 F 题意 分析 G 题意 分析 H 题意 分析 I 题意 分析 J 题意 分析 K 题意 分析 Summary: Ym:铁牌++ Czh: 原文地址:https://www.cnblogs.com/Deadline/p/9601892.html

hdu 5441 (2015长春网络赛E题 带权并查集 )

n个结点,m条边,权值是 从u到v所花的时间 ,每次询问会给一个时间,权值比 询问值小的边就可以走 从u到v 和从v到u算不同的两次 输出有多少种不同的走法(大概是这个意思吧)先把边的权值 从小到大排序 询问值也按从小到大排序num记录集合里元素的个数每合并两个集合 ans增加 2*num[u]*num[v] Sample Input15 5 3 //n w q2 3 63341 5 157243 5 57054 3 123821 3 2172660001000013000 Sample Out

2017省夏令营Day8 【bfs,并查集】

题解:出题人丧心病狂~ 对于这道题,我们对每一个内应节点bfs,并用并查集维护,如果s和t联通,输出答案并break. PS几个小细节:①对于每个内应dis=0,为了保证不会对答案产生影响,我们在每2个节点中插入一个新的节点即可: ②因为加入新节点,数组要开大些,否则会炸. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define Max 2020304 5 using nam

2017湘潭大学邀请赛H题(树的直径)

链接:https://www.icpc.camp/contests/4mYguiUR8k0GKE H. Highway The input contains zero or more test cases and is terminated by end-of-file. For each test case: The first line contains an integer n. The i-th of the following (n ? 1) lines contains three

HDU 6240 Server(2017 CCPC哈尔滨站 K题,01分数规划 + 树状数组优化DP)

题目链接  2017 CCPC Harbin Problem K 题意  给定若干物品,每个物品可以覆盖一个区间.现在要覆盖区间$[1, t]$. 求选出来的物品的$\frac{∑a_{i}}{∑b_{i}}$的最小值. 首先二分答案,那么每个物品的权值就变成了$x * b_{i} - a_{i}$ 在判断的时候先把那些权值为正的物品全部选出来, 然后记录一下从$1$开始可以覆盖到的最右端点的位置. 接下来开始DP,按照区间的端点升序排序(左端点第一关键字,右端点第二关键字) 问题转化为能否用剩