2019.01.10 bzoj1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
传送门
蒟蒻真正意义上做的第一道动态点分治!
题意:给一棵最开始所有点都是黑点的树,支持把点的颜色变成从黑/白色变成白/黑色,问当前状态树上两个最远黑点的距离。
思路:
首先考虑不带修改一次点分治怎么做的。
显然对于每个树上的节点ppp可以对它的每一个儿子vvv维护一个静态的集合BvB_vBv表示vvv子树中所有点到ppp的距离,然后对于ppp这个点可以维护一个静态集合CpC_pCp来记录所有maxBvmax_{B_v}maxBv,因此对于这个子树所有经过点ppp的答案就是CpC_pCp中的最大值和次大值之和,然后用一个静态集合AAA来维护所有点的答案CiC_iCi。
这样可以处理静态的。
那么考虑在一个点变化之后,A,B,CA,B,CA,B,C好像都会发生变化,然后如果我们建出点分树的话会发现变化只对于点分树上面这个点到根节点这条路径上面的点有影响。
那么我们将上述的集合变成动态的修改一下就可以了。
代码:
#include<bits/stdc++.h>
#define ri register int
#define pb push_back
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=200005;
int n,q;
int all,rt,fa[N],siz[N],msiz[N],dep[N],hson[N],top[N],Fa[N];
bool vis[N],del[N];
vector<int>e[N];
struct Que{
priority_queue<int>a,b;
inline void push(int x){a.push(x);}
inline void del(int x){b.push(x);}
inline int size(){return a.size()-b.size();}
inline void pop(){while(b.size()&&a.top()==b.top())a.pop(),b.pop();a.pop();}
inline int top(){while(b.size()&&a.top()==b.top())a.pop(),b.pop();return a.top();}
inline int stop(){int tmp=top(),ret;return pop(),ret=top(),push(tmp),ret;}
}A,B[N],C[N];
void dfs1(int p){
siz[p]=1;
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==Fa[p])continue;
Fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
if(siz[v]>siz[hson[p]])hson[p]=v;
}
}
void dfs2(int p,int tp){
top[p]=tp;
if(!hson[p])return;
dfs2(hson[p],tp);
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])!=Fa[p]&&v!=hson[p])dfs2(v,v);
}
}
inline int lca(int u,int v){
while(top[u]^top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=Fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
inline int dist(int u,int v){return dep[u]+dep[v]-2*dep[lca(u,v)];}
void getroot(int p,int fax){
siz[p]=1,msiz[p]=0;
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fax||vis[v])continue;
getroot(v,p),siz[p]+=siz[v],msiz[p]=max(msiz[p],siz[v]);
}
msiz[p]=max(msiz[p],all-siz[p]);
if(msiz[p]<msiz[rt])rt=p;
}
void solve(int p,int fat){
C[rt].push(dist(p,fa[rt]));
for(ri i=0,v;i<e[p].size();++i){
if((v=e[p][i])==fat||vis[v])continue;
solve(v,p);
}
}
inline void pushans(int p){if(B[p].size()>=2)A.push(B[p].top()+B[p].stop());}
inline void deleans(int p){if(B[p].size()>=2)A.del(B[p].top()+B[p].stop());}
void dfs(int p){
vis[p]=1,solve(p,0),B[p].push(0);
for(ri i=0,v;i<e[p].size();++i){
if(vis[v=e[p][i]])continue;
all=siz[v],rt=0,getroot(v,0),fa[v=rt]=p,dfs(rt),B[p].push(C[v].top());
}
pushans(p);
}
inline void On(int p){
deleans(p),B[p].del(0),pushans(p);
for(ri i=p;fa[i];i=fa[i]){
deleans(fa[i]),B[fa[i]].del(C[i].top()),C[i].del(dist(p,fa[i]));
if(C[i].size())B[fa[i]].push(C[i].top());
pushans(fa[i]);
}
}
inline void Off(int p){
deleans(p),B[p].push(0),pushans(p);
for(ri i=p;fa[i];i=fa[i]){
deleans(fa[i]);
if(C[i].size())B[fa[i]].del(C[i].top());
C[i].push(dist(p,fa[i])),B[fa[i]].push(C[i].top()),pushans(fa[i]);
}
}
int main(){
freopen("lx.in","r",stdin);
n=read();
for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].pb(v),e[v].pb(u);
dfs1(1),dfs2(1,1);
msiz[rt=0]=all=n,getroot(1,0),dfs(rt);
int tot=n;
for(ri tt=read();tt;--tt){
char s[2];
scanf("%s",s);
if(s[0]=='G'){
if(tot==1)puts("0");
else if(tot==0)puts("-1");
else cout<<A.top()<<'\n';
}
else{
int x=read();
del[x]^=1;
if(!del[x])Off(x),++tot;
else On(x),--tot;
}
}
return 0;
}
2019.01.10 bzoj1095: [ZJOI2007]Hide 捉迷藏(动态点分治)的更多相关文章
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...
- BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
- 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆
题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆
写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...
随机推荐
- pd.concat()命令
这个生成dataframe函数还是蛮有意思的.
- PHP面向对象之类的自动加载
类的自动加载 含义: 当某行代码需要一个类的时候,php的内部机制可以做到“自动加载该类文件”,以满足该行需要一个类的这种需求. 什么时候需要一个类? 1,new一个对象的时候: 2,使用一个类的静态 ...
- how2j网站前端项目——天猫前端(第一次)学习笔记7
开始学习结算页面 结算页面分为3个部分学习:1.简单的头部和收货地址 2.较为复杂的确认订单信息 3.交互 一.简单的头部和收货地址 根据站长的图片,自己模仿着做了一下,刚开始没有想到填写信息的4个框 ...
- coding利用Webhook实现Push代码后的jenkins自动构建
安装jenkins 篇:http://www.cnblogs.com/loveyouyou616/p/8714544.html 之前部署了持续集成工具jenkins.通常是开发后的代码先推到 远程代码 ...
- rosrun和roslaunch
rosrun allows you to run an executable(可执行) in an arbitrary(任意) package without having to cd (or ros ...
- HashMap从源码分析数据结构
1. HashMap在链表中存储的是键值对 2. 数组是一块连续的固定长度的内存空间,再好的哈希函数也不能保证得到的存储地址绝对不发生冲突.那么哈希冲突如何解决呢?哈希冲突的解决方案有多种:开放定址法 ...
- sqlserver中为节约存储空间的收缩数据库机制
1.收缩数据库: 删除数据库的每个文件中已经分配单还没有使用的页,首座后数据库空间自动减少 2.收缩方式: (1)自动收缩数据库 选中数据库--->右击--->属性 在常规这里我们可以看到 ...
- c++ 备忘
一.类型转换#include <sstream>stringstream ss;ss<<reverse(s1)<<'\t'<<reverse(s2);s ...
- PAT 1022 D进制的A+B (20)(20 分)
输入两个非负10进制整数A和B(<=2^30^-1),输出A+B的D (1 < D <= 10)进制数. 输入格式: 输入在一行中依次给出3个整数A.B和D. 输出格式: 输出A+B ...
- IDEA 的主题设置
1.主题设置(Appearance& Behavior) 补充1:设置编辑区的主题 (1)IDEA提供了两个编辑区的主题,如下所示 (2)如果想要更多的主题效果,可以到 http://www. ...