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;
}
HDU 6271 Master of Connected Component(2017 CCPC 杭州 H题,树分块 + 并查集的撤销)的更多相关文章
- HDU 6268 Master of Subgraph (2017 CCPC 杭州 E题,树分治 + 树上背包)
题目链接 2017 CCPC Hangzhou Problem E 题意 给定一棵树,每个点有一个权值,现在我们可以选一些连通的点,并且把这点选出来的点的权值相加,得到一个和. 求$[1, m] ...
- 2017 CCPC秦皇岛 H题 Prime set
Given an array of integers , we say a set is a prime set of the given array, if and is prime. Ba ...
- [HDU6271]Master of Connected Component
[HDU6271]Master of Connected Component 题目大意: 给出两棵\(n(n\le10000)\)个结点的以\(1\)为根的树\(T_a,T_b\),和一个拥有\(m( ...
- 2017 ccpc哈尔滨 A题 Palindrome
2017 ccpc哈尔滨 A题 Palindrome 题意: 给一个串\(T\),计算存在多少子串S满足\(S[i]=S[2n−i]=S[2n+i−2](1≤i≤n)\) 思路: 很明显这里的回文串长 ...
- HDU 6270 Marriage (2017 CCPC 杭州赛区 G题,生成函数 + 容斥 + 分治NTT)
题目链接 2017 CCPC Hangzhou Problem G 题意描述很清晰. 考虑每个家庭有且仅有$k$对近亲的方案数: $C(a, k) * C(b, k) * k!$ 那么如果在第$1$ ...
- Valentine'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 (Ja ...
- 2017 CCPC 杭州 流水账
day0: 队内训练ccpc 秦皇岛,敝校自己出的题,感觉一个星期没怎么写代码,手生得很,不出意料被打飞了. day1 (热身赛): 热身赛还算顺利,A题看有的队几分钟就草过去了,还以为又是西安ICP ...
- 2017 CCPC秦皇岛 A题 A Ballon Robot
The 2017 China Collegiate Programming Contest Qinhuangdao Site is coming! There will be teams parti ...
- 2017 CCPC 杭州 HDU6273J 区间修改(线段树&差分数组)
http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf 解析 线段树区间延迟更新 或 差分数组 两个数 统计2和3的最少的 ...
随机推荐
- Python+Selenium框架设计篇之-什么是POM
前面我们介绍了Python中的单元测试框架unittest,以后我们所有的测试类文件,都采用unittest来辅助我们进行debug和脚本开发.搞定了debug机制和确定了unittest来进行创建和 ...
- Jmeter日期
有的时候我们接口中会有需要传递日期的参数,这是jmeter工具中给我准备一个 日期函数_time,如下图所示: 取到的将会是年月日 对应的写法有 yyyy-MM-dd HH:mm:ss ---年月日 ...
- Mysql与Oracle之间的数据类型转换
MySQL Data Type Oracle Data Type BIGINT NUMBER(19, 0) BIT RAW BLOB BLOB, RAW CHAR CHAR DATE DATE DAT ...
- java中利用正则表达式获取a标签
// 设置新闻内容 notice.setContent(editorValue); Matcher m = Pattern.compile("<a[^>]*>([^< ...
- ZOJ 3544 / HDU 4056 Draw a Mess( 并查集好题 )
方法参见:http://blog.acmol.com/?p=751 从最后一个线段开始倒着处理(因为之后的线段不会被它之前的线段覆盖),把这条线段所覆盖的所有线段编号合并到一个集合里,并以最左边线段编 ...
- 【转】通过制作Flappy Bird了解Native 2D中的RigidBody2D和Collider
作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 引子 在第一篇文章[Unity3D基础教程] ...
- 六、vue侦听属性
$watch 实际上无论是 $watch 方法还是 watch 选项,他们的实现都是基于 Watcher 的封装.首先我们来看一下 $watch 方法,它定义在 src/core/instance/s ...
- iOS大神班笔记02-模仿苹果创建单例
首先我们得要知道苹果是如何实现单例的:1.不能外界调用alloc,一调用就崩掉,其实就是抛异常(类内部第一次调用alloc就不崩溃,其他都崩溃). 2.提供一个方法给外界获取单例. 3.内部创建一次 ...
- 详解Django-auth-ldap 配置方法
使用场景 公司内部使用Django作为后端服务框架的Web服务,当需要使用公司内部搭建的Ldap 或者 Windows 的AD服务器作为Web登录认证系统时,就需要这个Django-auth-ldap ...
- POJ 1064 Cable master | 二分+精度
题目: 给n个长度为l[i](浮点数)的绳子,要分成k份相同长度的 问最多多长 题解: 二分长度,控制循环次数来控制精度,输出也要控制精度<wa了好多次> #include<cstd ...