动态点分治

先建出点分树,每个点上维护两个堆,s1,s2,分别表示子树中到点分树中父亲的所有长度,每个儿子s1的最大值,那么对于每个点答案就是s2的最大+次大,再维护一个s3保存这个。

首先我们要搞一个带删除的堆,那么我们开两个堆就行了,一个保存元素,一个保存被删除的元素,每次一起弹出就行了

然后是为什么要维护三个堆,每个点记录所有儿子的路径不行吗》这里我想了很长时间,其实很简单,因为记录路径的话有可能最大和次大都是从一个儿子里来的。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + ;
int rd()
{
int x = , f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x = x * + c - ''; c = getchar(); }
return x * f;
}
int n, sum, m, root;
int size[N], f[N], vis[N], val[N], dep[N], fa[N][], Fa[N];
vector<int> G[N];
struct Heap {
priority_queue<int> A, B;
void push(int x) { A.push(x); }
void del(int x) { B.push(x); }
int top()
{
while(!A.empty() && !B.empty() && A.top() == B.top()) A.pop(), B.pop();
return A.top();
}
int sum()
{
int x = top();
A.pop();
int y = top();
A.push(x);
return x + y;
}
int size()
{
return A.size() - B.size();
}
} s1[N], s2[N], s3;
void erase(Heap &s)
{
if(s.size() > ) s3.del(s.sum());
}
void Insert(Heap &s)
{
if(s.size() > ) s3.push(s.sum());
}
void dfs(int u, int last)
{
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
if(v == last) continue;
fa[v][] = u;
dep[v] = dep[u] + ;
dfs(v, u);
}
}
int lca(int u, int v)
{
if(dep[u] < dep[v]) swap(u, v);
int d = dep[u] - dep[v];
for(int i = ; i >= ; --i)
if(d & ( << i))
u = fa[u][i];
if(u == v) return u;
for(int i = ; i >= ; --i)
if(fa[u][i] != fa[v][i])
u = fa[u][i],
v = fa[v][i];
return fa[u][];
}
int getsize(int u, int last)
{
int ret = ;
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
if(v == last || vis[v]) continue;
ret += getsize(v, u);
}
return ret;
}
void getroot(int u, int last, int S)
{
f[u] = ;
size[u] = ;
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
if(v == last || vis[v]) continue;
getroot(v, u, S);
size[u] += size[v];
f[u] = max(f[u], size[v]);
}
f[u] = max(f[u], S - size[u]);
if(f[u] < f[root]) root = u;
}
void divide(int u)
{
vis[u] = ;
for(int i = ; i < G[u].size(); ++i)
{
int v = G[u][i];
if(vis[v]) continue;
root = ;
getroot(v, u, getsize(v, u));
Fa[root] = u;
divide(root);
}
}
int dis(int u, int v)
{
int x = lca(u, v);
return dep[u] + dep[v] - * dep[x];
}
void join(int u)
{
int tmp = u;
erase(s2[u]);
s2[u].push();
Insert(s2[u]);
while(Fa[u])
{
erase(s2[Fa[u]]);
if(s1[u].size()) s2[Fa[u]].del(s1[u].top());
s1[u].push(dis(Fa[u], tmp));
s2[Fa[u]].push(s1[u].top());
Insert(s2[Fa[u]]);
u = Fa[u];
}
}
void remove(int u)
{
int tmp = u;
erase(s2[u]);
s2[u].del();
Insert(s2[u]);
while(Fa[u])
{
erase(s2[Fa[u]]);
s2[Fa[u]].del(s1[u].top());
s1[u].del(dis(tmp, Fa[u]));
if(s1[u].size()) s2[Fa[u]].push(s1[u].top());
Insert(s2[Fa[u]]);
u = Fa[u];
} }
int main()
{
f[] = 1e9;
n = sum = rd();
for(int i = ; i < n; ++i)
{
int u = rd(), v = rd();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(, );
for(int j = ; j <= ; ++j)
for(int i = ; i <= n; ++i)
fa[i][j] = fa[fa[i][j - ]][j - ];
getroot(, , getsize(, ));
divide(root);
m = rd();
for(int i = ; i <= n; ++i) join(i), val[i] = ;
while(m--)
{
char opt[];
scanf("%s", opt);
if(opt[] == 'G')
{
if(sum < ) printf("%d\n", sum - );
else printf("%d\n", s3.top());
}
if(opt[] == 'C')
{
int u = rd();
if(val[u] == )
{
val[u] = ;
remove(u);
--sum;
}
else
{
val[u] = ;
join(u);
++sum;
}
}
}
return ;
}

bzoj1095的更多相关文章

  1. 【BZOJ1095】捉迷藏(动态点分治)

    [BZOJ1095]捉迷藏(动态点分治) 题面 BZOJ 题解 动态点分治板子题 假设,不考虑动态点分治 我们来想怎么打暴力: \(O(n)DP\)求树的最长链 一定都会.不想解释了 所以,利用上面的 ...

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

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

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

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

  4. 【bzoj1095】 ZJOI2007—捉迷藏

    http://www.lydsy.com/JudgeOnline/problem.php?id=1095 (题目链接) 题意 一棵树,求最远的两黑点之间的距离,每次可以将黑点染白或者将白点染黑. So ...

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

    题目链接 BZOJ1095 题解 传说中的动态点分治,一直不敢碰 今日一会,感觉其实并不艰涩难懂 考虑没有修改,如果不用树形dp的话,就得点分治 对于每个重心,我们会考虑其分治的子树内所有点到它的距离 ...

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

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

  7. [bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

    [bzoj1095][ZJOI2007]Hide 捉迷藏 2015年4月20日7,8876 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiaji ...

  8. BZOJ1095 [ZJOI2007]Hide 捉迷藏

    动态树分治,用三个set分别维护每个重心到每一个子树的距离种类.每个重心所有子树的最大值和次大值.全局答案的最大值.复杂度O(nlogn^2) 代码 #include<cstdio> #i ...

  9. bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治

    这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...

  10. 【BZOJ1095】 Hide 捉迷藏

    Time Limit: 4000 ms   Memory Limit: 256 MB Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.W ...

随机推荐

  1. Android——滑动事件冲突解决

    android中的事件类型分为按键事件和屏幕触摸事件,Touch事件是屏幕触摸事件的基础事件. android系统中的每个View的子类都具有下面三个与TouchEvent处理密切相关的方法: (1) ...

  2. Linux C高级编程——网络编程基础(1)

    Linux高级编程--BSD socket的网络编程 宗旨:技术的学习是有限的,分享的精神是无限的. 一网络通信基础 TCP/IP协议簇基础:之所以称TCP/IP是一个协议簇,是由于TCP/IP包括T ...

  3. Solaris shell脚本学习

    看懂脚本文件即可 知识点: Shell概述 Shell变量 Shell中的特殊字符 参数置换变量 控制结构 何为shell Shell就是unix提供给用户的使用界面,处于内核和应用程序之间,他是一个 ...

  4. 【Bootstrap】一个兼容IE8、谷歌等主流浏览器的受众门户式风格页面

    上一次写的<[Bootstrap]一个兼容IE8.谷歌等主流浏览器的受众巨幕式风格页面>(点击打开链接) 部分老一辈的需求可能对这样的后现代的风格并不惬意, 没关系,我们全然能够改变布局 ...

  5. Android Volley分析(一)——结构

    Volley是Android系统下的一个网络通信库.为Android提供简单高速的网络操作(Volley:Esay, Fast Networking for Android),以下是它的结构: 既然是 ...

  6. HBase写请求分析

    HBase作为分布式NoSQL数据库系统,不单支持宽列表.而且对于随机读写来说也具有较高的性能.在高性能的随机读写事务的同一时候.HBase也能保持事务的一致性. 眼下HBase仅仅支持行级别的事务一 ...

  7. 超实用的 Nginx 极简教程,覆盖了常用场景(转)

    概述 安装与使用 安装 使用 nginx 配置实战 http 反向代理配置 负载均衡配置 网站有多个 webapp 的配置 https 反向代理配置 静态站点配置 搭建文件服务器 跨域解决方案 参考 ...

  8. Apache Thrift的简单介绍

    1.什么是Thrift thrift是一种可伸缩的跨语言服务的发展软件框架.它结合了功能强大的软件堆栈的代码生成引擎,以建设服务.不同开发语言开发的服务可以通过该框架实现通信. thrift是face ...

  9. xcode7和ios9下UIWebView不能加载网页的解决方法

    错误描述: App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecu ...

  10. "php"正则表达式使用总结

    一直对php的正则表达式的理解不是很深刻,而且是很一知半解,所以把自己用的的正则表达式总结下,以后方便查阅,以后遇到正则表达式的时候然后再追加到该文档的后面: /** * php常用正则表达式 * p ...