bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆
Description
捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩
捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋
子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的
时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要
求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两
个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange) i 改变第i个房
间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的
距离。
Input
第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。接下来N-1行每行两个整数a, b,
表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如
上文所示。
Output
对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关
着灯的,输出0;若所有房间的灯都开着,输出-1。
Sample Input
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G
Sample Output
3
3
4
HINT
对于100%的数据, N ≤100000, M ≤500000。
题目大意
给定一棵树,每个点的颜色不是黑色就是白色,开始所有点的颜色都是黑色,要求支持两个操作:
- 翻转一个点的颜色
- 询问最远的黑点对的距离。如果只有1个黑点,那么输出0,如果没有黑点,输出-1。
由于有多次询问,所以不可能暴力求最长链。
如何快速处理最长链?于是想到了点分治。
现在的任务是让点分治支持修改操作。
因为最长距离不可加减,所以只能通过维护分治中心的各子树中,深度最大的点,然后取前两大更新答案。
因此,每个点维护两个堆,一个堆维护点分树上它的子树中深度最大的点的深度,一个堆维护在点分树上它的子树中所有点到它的父分治中心的距离。
除此之外,还要开一个全局堆维护答案。
对于修改操作,就是删除元素再插入元素,自己画画图就能想清楚(明明是yyf扯不清楚)。
问题是怎么让堆支持删除?再开个堆打标记就好了。
还有一个问题,如何求树上两点间的距离?两点的深度减去它们LCA的深度的两倍,求LCA用st表。
Code
/**
* bzoj
* Problem#1095
* Accepted
* Time: 13356ms
* Memory: 159584k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;
const signed int inf = (signed) (~0u >> ) - ; typedef class Node {
public:
int val;
Node *l, *r; Node(int val = , Node* l = NULL, Node* r = NULL):val(val), l(l), r(r) { }
}Node; Node* merge(Node* a, Node* b) {
if(!a) return b;
if(!b) return a;
if(a->val < b->val) swap(a, b);
a->r = merge(a->r, b);
swap(a->l, a->r);
return a;
} #define Limit 10000000
Node pool[Limit];
Node *top = pool; Node* newnode(int x) {
if(top >= pool + Limit)
return new Node(x, NULL, NULL);
top->val = x;
return top++;
} #define clr(rt, dr) while(rt && dr && dr->val == rt->val) rt = merge(rt->l, rt->r), dr = merge(dr->l, dr->r)
typedef class Heap {
public:
int s;
Node* rt;
Node* dr; Heap():s(), rt(NULL), dr(NULL) { } int top() {
if(!rt) return -;
return rt->val;
} int sectop() {
if(!rt) return -inf;
clr(rt->l, dr);
clr(rt->r, dr);
int lv = (rt->l) ? (rt->l->val) : (-inf), rv = (rt->r) ? (rt->r->val) : (-inf);
return (lv > rv) ? (lv) : (rv);
} void pop() {
rt = merge(rt->l, rt->r);
clr(rt, dr);
} void insert(int x) {
if(x < ) return;
s++;
rt = merge(rt, newnode(x));
clr(rt, dr);
} void remove(int x) {
if(x < ) return;
s--;
dr = merge(dr, newnode(x));
clr(rt, dr);
} int size() {
return s;
}
}Heap; const int N = 1e5 + ; int n, m, n2;
vector<int> *g;
Heap *dtg, *dtf, gol;
int *siz, *fag, *dep, *erl;
int *Log2, *in;
boolean *vis, *ison; inline void init() {
scanf("%d", &n), n2 = n << ;
g = new vector<int>[(n + )];
dtg = new Heap[(n + )];
dtf = new Heap[(n + )];
in = new int[(n + )];
siz = new int[(n + )];
fag = new int[(n + )];
dep = new int[(n + )];
erl = new int[(n2 + )];
Log2 = new int[(n2 + )];
vis = new boolean[(n + )];
ison = new boolean[(n + )];
fill(vis + , vis + n + , false);
fill(ison + , ison + n + , false);
for(int i = , u, v; i < n; i++) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
} int cerl = ;
void dfs1(int p, int fa) {
erl[++cerl] = p;
in[p] = cerl;
dep[p] = dep[fa] + ;
for(int i = ; i < (signed)g[p].size(); i++) {
int e = g[p][i];
if(e == fa) continue;
dfs1(e, p);
erl[++cerl] = p;
}
} #define bzmax 19
int st[][N << ];
inline void init_st() {
Log2[] = , dep[] = ;
for(int i = ; i <= n2; i++)
Log2[i] = Log2[i >> ] + ;
dfs1(, ); for(int i = ; i < n2 - ; i++)
st[][i] = (dep[erl[i]] < dep[erl[i + ]]) ? (erl[i]) : (erl[i + ]);
for(int j = ; j < bzmax; j++)
for(int i = , a, b; i + ( << j) < n2; i++) {
a = st[j - ][i], b = st[j - ][i + ( << (j - ))];
st[j][i] = (dep[a] < dep[b]) ? (a) : (b);
}
} inline int Lca(int u, int v) {
int l = in[u], r = in[v], len, a, b;
if(l > r) swap(l, r);
len = Log2[r - l + ];
a = st[len][l], b = st[len][r - ( << len) + ];
return (dep[a] < dep[b]) ? (a) : (b);
} inline int dist(int u, int v) {
int lca = Lca(u, v);
return dep[u] + dep[v] - (dep[lca] << );
} void dfs2(int p, int fa) {
siz[p] = ;
for(int i = ; i < (signed)g[p].size(); i++) {
int e = g[p][i];
if(e == fa || vis[e]) continue;
dfs2(e, p);
siz[p] += siz[e];
}
} void dfs3(int p, int fa, int& cov, int& G, int& maxv) {
int cmp = cov - siz[p];
for(int i = ; i < (signed)g[p].size(); i++) {
int e = g[p][i];
if(e == fa || vis[e]) continue;
dfs3(e, p, cov, G, maxv);
cmp = (siz[e] > cmp) ? (siz[e]) : (cmp);
}
if(cmp < maxv)
maxv = cmp, G = p;
} void dfs4(int p, int fa, int dep, int G, int fG) {
if(fG) dtf[G].insert(dist(p, fG));
for(int i = ; i < (signed)g[p].size(); i++) {
int e = g[p][i];
if(e == fa || vis[e]) continue;
dfs4(e, p, dep + , G, fG);
}
} #define get_val(h) (h.size() <= 1) ? ((h.size() == 1) ? (0) : (-1)) : (h.top() + h.sectop())
int dividing(int p, int fag) {
dfs2(p, );
int G, maxv = inf, sG;
dfs3(p, , siz[p], G, maxv);
vis[G] = true, ::fag[G] = fag;
dfs4(G, , , G, fag);
dtg[G].insert();
for(int i = ; i < (signed)g[G].size(); i++) {
int e = g[G][i];
if(vis[e]) continue;
sG = dividing(e, G);
dtg[G].insert(dtf[sG].top());
}
gol.insert(get_val(dtg[G]));
return G;
} void turn_on(int p) {
int G = p, oldt = , newt = -;
ison[p] = true;
while (G) {
if(oldt != newt) {
gol.remove(get_val(dtg[G]));
dtg[G].remove(oldt);
if(~newt) dtg[G].insert(newt);
gol.insert(get_val(dtg[G]));
}
if (fag[G]) {
oldt = dtf[G].top();
dtf[G].remove(dist(p, fag[G]));
newt = dtf[G].top();
}
G = fag[G];
}
} void turn_off(int p) {
int G = p, oldt = -, newt = ;
ison[p] = false;
while (G) {
if(oldt != newt) {
gol.remove(get_val(dtg[G]));
if(~oldt) dtg[G].remove(oldt);
dtg[G].insert(newt);
gol.insert(get_val(dtg[G]));
}
if(fag[G]) {
oldt = dtf[G].top();
dtf[G].insert(dist(p, fag[G]));
newt = dtf[G].top();
}
G = fag[G];
}
} inline void solve() {
scanf("%d", &m);
char buf[];
int x;
while (m--) {
scanf("%s", buf);
if(buf[] == 'G') {
int x = gol.top();
printf("%d\n", x);
} else {
scanf("%d", &x);
if(ison[x])
turn_off(x);
else
turn_on(x);
}
}
} int main() {
init();
init_st();
dividing(, );
solve();
return ;
}
bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆的更多相关文章
- 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆
题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆
写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...
- [BZOJ]1095 Hide捉迷藏(ZJOI2007)
一道神题,两种神做法. Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特 ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...
随机推荐
- C语言记录汇总
uint32_t 转载自:http://blog.sina.com.cn/s/blog_6aea878e0100tl0f.html体会1>. 在写程序时注意"无符号类型&quo ...
- 连接mysql && ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)
上一篇:mysql服务正在启动 mysql服务无法启动 && mysql启动脚本 mysql关闭脚本 此篇目编写一个核心目的: 1.mysql连接 先抛出一个问题 这是因为mysql服 ...
- 纯HTML和CSS实现点击切换
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 18. 4Sum(双指针)
Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums s ...
- python-demo实例
1.turtle库与蟒蛇案例 import turtle def drawSnake(rad,angle,len,neckrad): for i in range(len): turtle.circl ...
- 【转】推荐4个不错的Python自动化测试框架
之前,开发团队接手一个项目并开始开发时,除了项目模块的实际开发之外,他们不得不为这个项目构建一个自动化测试框架.一个测试框架应该具有最佳的测试用例.假设(assumptions).脚本和技术来运行每一 ...
- Another Meaning (KMP + DP)
先用KMP重叠匹配求出各个匹配成功的尾串位置.然后利用DP去求,那转移方程应该是等于 上一个状态 (无法匹配新尾巴) 上一个状态 + 以本次匹配起点为结尾的状态(就是说有了新的位置) + 1 (单单一 ...
- 【Linux学习九】负载均衡
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 一.高并发 随着应用访问量的增加,带来高并发处理问题. 具体有两个: ...
- jfinal 项目 控制层、ORM层、AOP层,在发表之前一定要记得保存
一.ORM简介 对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术.简单的说,ORM是通过使用描述对象和数据 ...
- 接口作为方法的参数或返回值——List接口
接口作为方法的参数或返回值,源码可知,List为一个接口,ArraryList是的它的实现类: 其中,addNames方法中,入参和返回值都List接口,入参是多态的,编译看左,运行看右(访问成员方法 ...