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

8

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

4

3

3

4

HINT

对于100%的数据, N ≤100000, M ≤500000。


思路

先讲一讲动态点分治做法

剩下的好像还有一个线段树维护括号序列明天填坑

树上路径问题,链剖行不通啊咋办

就想用点分治做,考虑经过每一个点的贡献

那么就先把点分树建出来,尝试进行维护发现是我们对于一个点分树上的节点,考虑所有他的字节点,分别管理了这个节点的所有的子树,我们要知道到每一个子树中黑色节点到这个点的距离并取出最大和次大

维护三个堆\(own,subtree,total\)

为了维护这个东西(最大和次大),我们先用\(own\)维护出每个节点所有管辖黑色节点到这个节点的点分树父亲节点的距离

然后我们记录\(subtree\)为每一个点分树上的节点的所有子树的节点到这个节点的最大值

那么为了方便更新答案,再用\(total\)记录每一个节点的\(subtree\)中最大和次大的和

注意每次修改一个节点的颜色的时候,它本身对自己的subtree堆是有一个0的长度的,如果不添加那你对于这个节点就默认他没有改变,就错了

其次是写的时候注意运算逻辑的先后顺序,不然会很可怕的

堆的维护。。。我是用两个堆实现的支持\(push,pop,top,max+secondmax\)的数据结构


#include<bits/stdc++.h>

using namespace std;

int read() {
int res = 0, w = 1; char c = getchar();
while (!isdigit(c) && c != '-') c = getchar();
if (c == '-') w = -1, c = getchar();
while (isdigit(c)) res = (res << 1) + (res << 3) + c - '0', c = getchar();
return res * w;
} const int N = 1e5 + 10;
const int LOG = 20; struct Heap {
priority_queue<int> a, b;
void push(int vl) {
a.push(vl);
}
void pop(int vl) {
b.push(vl);
}
int size() {
return a.size() - b.size();
}
int top() {
while (b.size() && a.top() == b.top()) {
a.pop();
b.pop();
}
if (a.size()) return a.top();
else return 0;
}
int calc() { //max + second_max
if (size() < 2) return 0;
int tp = top();
pop(tp);
int res = top() + tp;
push(tp);
return res;
}
}; struct Edge {
int v, nxt;
Edge(int v = 0, int nxt = 0): v(v), nxt(nxt) {}
} E[N << 1];
int head[N], tot = 0;
int n, q, num = 0, col[N] = {0};
char c[10]; void addedge(int u, int v) {
E[++tot] = Edge(v, head[u]);
head[u] = tot;
} namespace LCA { struct Node {
int id, depth;
Node(int id = 0, int depth = 0): id(id), depth(depth) {}
bool operator < (const Node b) const {
return depth < b.depth;
}
} ST[N << 1][LOG];
int first[N], dep[N], log[N << 1], len; void dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
ST[++len][0] = Node(u, dep[u]);
first[u] = len;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa) continue;
dfs(v, u);
ST[++len][0] = Node(u, dep[u]);
}
} void init() {
dfs(1, 0);
log[1] = 0;
for (int i = 2; i <= len; i++) log[i] = log[i >> 1] + 1;
for (int j = 1; (1 << j) <= len; j++) {
for (int i = 1; i + (1 << j) - 1 <= len; i++) {
ST[i][j] = min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
}
}
} int getdis(int u, int v) {
if (first[u] < first[v]) swap(u, v);
int k = log[first[u] - first[v] + 1];
int lca = min(ST[first[v]][k], ST[first[u] - (1 << k) + 1][k]).id;
return dep[u] + dep[v] - (dep[lca] << 1);
} } namespace Tree_Devide { Heap total, subtree[N], own[N];
int father[N];
int siz[N], F[N], siz_all, rt;
bool vis[N]; void getsiz(int u, int fa) {
siz[u] = 1;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
getsiz(v, u);
siz[u] += siz[v];
}
} void getroot(int u, int fa) {
F[u] = 0;
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v == fa || vis[v]) continue;
getroot(v, u);
F[u] = max(F[u], siz[v]);
}
F[u] = max(F[u], siz_all - siz[u]);
if (F[u] < F[rt]) rt = u;
} void solve(int u, int fa) {
father[u] = fa;
vis[u] = 1;
getsiz(u, 0);
for (int i = head[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v]) continue;
F[rt = 0] = siz_all = siz[v];
getroot(v, 0);
solve(rt, u);
}
} void init() {
getsiz(1, 0);
F[rt = 0] = siz_all = n;
getroot(1, 0);
solve(rt, 0);
} void turn_off(int u) {
subtree[u].push(0);
if (subtree[u].size() == 2) total.push(subtree[u].calc());
for (int cur = u; father[cur]; cur = father[cur]) {
int dis = LCA::getdis(u, father[cur]);
int lasttop = own[cur].top();
own[cur].push(dis);
if (dis <= lasttop) continue;
int lastmax = subtree[father[cur]].calc(), lastsiz = subtree[father[cur]].size();
if (lasttop) subtree[father[cur]].pop(lasttop);
subtree[father[cur]].push(dis);
int nowmax = subtree[father[cur]].calc(), nowsiz = subtree[father[cur]].size();
if (nowmax > lastmax) {
if (lastsiz >= 2) total.pop(lastmax);
if (nowsiz >= 2) total.push(nowmax);
}
}
} void turn_on(int u) {
if (subtree[u].size() == 2) total.pop(subtree[u].calc());
subtree[u].pop(0);
for (int cur = u; father[cur]; cur = father[cur]) {
int dis = LCA::getdis(u, father[cur]);
int lasttop = own[cur].top();
own[cur].pop(dis);
if (dis != lasttop) continue;
int lastmax = subtree[father[cur]].calc(), lastsiz = subtree[father[cur]].size();
subtree[father[cur]].pop(dis);
if (own[cur].top()) subtree[father[cur]].push(own[cur].top());
int nowmax = subtree[father[cur]].calc(), nowsiz = subtree[father[cur]].size();
if (nowmax < lastmax) {
if (lastsiz >= 2)total.pop(lastmax);
if (nowsiz >= 2) total.push(nowmax);
}
}
} } int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
n = read();
for (int i = 1; i < n; i++) {
int u = read(), v = read();
addedge(u, v);
addedge(v, u);
}
LCA::init();
Tree_Devide::init();
for (int i = 1; i <= n; i++) Tree_Devide::own[i].push(0);
for (int i = 1; i <= n; i++) {
++num;
Tree_Devide::turn_off(i);
}
q = read();
while (q--) {
scanf("%s", c);
if (c[0] == 'C') {
int u = read();
if (col[u]) Tree_Devide::turn_off(u), tot++;
else Tree_Devide::turn_on(u), tot--;
col[u] ^= 1;
} else {
if (num == 0) printf("-1\n");
else if (num == 1) printf("0\n");
else printf("%d\n", Tree_Devide::total.top());
}
}
return 0;
}

BZOJ1095: [ZJOI2007]Hide 捉迷藏【动态点分治】的更多相关文章

  1. BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...

  2. bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习

    好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...

  3. BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)

    Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...

  4. 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

  5. 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆

    题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...

  6. 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)

    题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...

  7. BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治

    [题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...

  8. BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)

    传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...

  9. BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆

    写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...

  10. 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏

    简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ...

随机推荐

  1. 禁止或强制使用堆分配---《C++必知必会》 条款34

    有时候,指明一些特定类的对象不应该被分配到堆(heap)上是个好主意.通常这是为了确保该对象的析构函数一定会得到调用.维护对象本身(body object)的引用计数的句柄对象(handle obje ...

  2. 限制可编辑div只能输入纯文本

    本博客转载自张鑫旭大神的一篇文章:小tip: 如何让contenteditable元素只能输入纯文本,原文地址:http://www.zhangxinxu.com/wordpress/2016/01/ ...

  3. sql server递归子节点、父节点,sql查询表结构,根据字段名查所在表

    一.查询当前部门下的所有子部门 WITH dept AS ( SELECT * FROM dbo.deptTab --部门表 WHERE pid = @id UNION ALL SELECT d.* ...

  4. java--jvm启动的参数

    java启动参数共分为三类其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容:其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保 ...

  5. 使用Vuejs编写单js组件

    1.引用方式 我们使用Vue进行普通页面开发却不使用webpack等技术时,定义组件可以只依赖单js文件进行开发 然后像正常引用js文件那样进行引用 <script src="../C ...

  6. 20145303刘俊谦《网络对抗》Exp2 后门原理与实践

    20145303刘俊谦<网络对抗>Exp2 后门原理与实践 基础问题回答 1.例举你能想到的一个后门进入到你系统中的可能方式? •在网页上浏览不安全的网站或者下载不安全的软件 •通过发送邮 ...

  7. java实验五20145204

    java实验 Tcp传输 实验内容 运行代码一人服务器,一人客户端. 下载加解密代码,先编译运行代码,一人加密一人解密,适当修改代码. 集成代码,一人加密后通过TCP发送,加密使用AES或DES,AE ...

  8. 20145315 《Java程序设计》第四周学习总结

    20145315 <Java程序设计>第四周学习总结 教材学习内容总结 第六章 继承与多态 6.1何谓继承 6.1.1继承共同行为 把相同的程序代码提升为父类 private String ...

  9. centos7下SVN服务器如何搭建

    Centos7 搭建svn服务器 linux(centos)下SVN服务器如何搭建?说到SVN服务器,想必大家都知道,可以是在LINUX下如何搭建SVN服务器呢?那么今天给大家分享一下linux(ce ...

  10. CSU 1963 Feed the rabbit(斜率优化dp)

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1963 题意:有m个坑,每只兔子会在ti时刻回到坑中,现在有n个人,每个人都可以从任意时间(&l ...