传送门

解题思路

  点分树其实就是在点分治的基础上,把重心连起来。这样树高是$log$的,可以套用数据结构进行操作。这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点的距离,再维护一个全局堆表示答案。修改的时候就从这个点开始暴力往上跳,每次修改到父节点的距离从而影响其父节点的子树的距离。时间复杂度$O(nlog^2n)$

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue> using namespace std;
const int N=100005; inline int rd(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x;
} void out(int x){
if(!x) return ;out(x/10);putchar('0'+x%10);
} inline int max(int x,int y){return x>y?x:y;} int n,head[N],cnt,to[N<<1],nxt[N<<1],Min,siz[N],m;
int dep[N],g[N][25],fa[N],Sum,rt,tot;
bool vis[N],open[N]; struct Heap{
priority_queue<int> del,Q;
inline void Push(int x) {Q.push(x);}
inline void Del(int x) {del.push(x);}
inline int Top(){
while(del.size() && Q.top()==del.top())
del.pop(),Q.pop();
return Q.top();
}
inline void Pop(){
while(del.size() && Q.top()==del.top())
del.pop(),Q.pop();
Q.pop();
}
inline int sec_Top(){
int tmp=Top(); Pop();
int ret=Top(); Push(tmp);
return ret;
}
inline int size(){return Q.size()-del.size();}
}f[N],c[N],ans; inline void add(int bg,int ed){
to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
} int top[N],son[N],Fa[N]; void dfs(int x,int F){
siz[x]=1; Fa[x]=F; int u,maxson=-1;
for(int i=head[x];i;i=nxt[i]){
u=to[i]; if(u==F) continue;
dep[u]=dep[x]+1; dfs(u,x); siz[x]+=siz[u];
if(siz[u]>maxson) maxson=siz[u],son[x]=u;
}
} void dfs2(int x,int topf){
top[x]=topf;if(!son[x]) return ;
dfs2(son[x],topf);int u;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==Fa[x] || u==son[x]) continue;
dfs2(u,u);
}
} inline void init(){
n=rd();int x,y;
for(int i=1;i<n;i++){
x=rd(),y=rd();
add(x,y); add(y,x);
}
dfs(1,0); dfs2(1,1);
} void dfs1(int x,int F){
siz[x]=1; int u;
for(int i=head[x];i;i=nxt[i]){
u=to[i]; if(vis[u] || u==F) continue;
dfs1(u,x); siz[x]+=siz[u];
}
} inline int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]) x=Fa[top[x]];
else y=Fa[top[y]];
}
return dep[x]<dep[y]?x:y;
} inline int DIS(int x,int y){
if(!x || !y) return 0;
int lca=LCA(x,y);
return dep[x]+dep[y]-2*dep[lca];
} void get_rt(int x,int F){
int Max=0,u;
for(register int i=head[x];i;i=nxt[i]){
u=to[i]; if(u==F || vis[u]) continue;
get_rt(u,x); Max=max(Max,siz[u]);
}
Max=max(Max,Sum-siz[x]);
if(Max<Min) {Min=Max;rt=x;}
} inline void get_dis(int x,int F,int pre){
f[pre].Push(DIS(fa[pre],x));
for(int i=head[x];i;i=nxt[i]){
int u=to[i]; if(vis[u] || u==F) continue;
get_dis(u,x,pre);
}
} inline void Insert(Heap &x){
if(x.size()>1) ans.Push(x.Top()+x.sec_Top());
} inline void Erase(Heap &x){
if(x.size()>1) ans.Del(x.Top()+x.sec_Top());
} int DFS(int x,int F){
dfs1(x,0); Sum=siz[x]; Min=Sum+1; get_rt(x,0);
int G=rt,son; fa[G]=F; vis[G]=1; Sum=0;
get_dis(G,0,G); c[G].Push(0); rt=0;
for(register int i=head[G];i;i=nxt[i]){
int u=to[i]; if(vis[u]) continue;
son=DFS(u,G); c[G].Push(f[son].Top());
}
Insert(c[G]);
return G;
} inline void solve_open(int x){
Erase(c[x]); c[x].Del(0); Insert(c[x]);
for(register int y=x;fa[y];y=fa[y]){
Erase(c[fa[y]]);
c[fa[y]].Del(f[y].Top());
f[y].Del(DIS(x,fa[y]));
if(f[y].size()) c[fa[y]].Push(f[y].Top());
Insert(c[fa[y]]);
}
} inline void solve_close(int x){
Erase(c[x]); c[x].Push(0); Insert(c[x]);
for(register int y=x;fa[y];y=fa[y]){
Erase(c[fa[y]]);
if(f[y].size()) c[fa[y]].Del(f[y].Top());
f[y].Push(DIS(x,fa[y]));
c[fa[y]].Push(f[y].Top());
Insert(c[fa[y]]);
}
} inline void work(){
char c=getchar();while(c!='C' && c!='G') c=getchar();
if(c=='G') {
if(tot<=1) printf("%d\n",tot-1);
else out(ans.Top()),putchar('\n');
}
else {
int x=rd();
if(!open[x]) tot--,solve_open(x),open[x]=1;
else tot++,solve_close(x),open[x]=0;
}
} int main(){
init(); DFS(1,0); m=rd(); tot=n;
while(m--) work();
return 0;
}

BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. BZOJ 1095: [ZJOI2007]Hide 捉迷藏

    Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...

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

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

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

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

  9. 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏

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

随机推荐

  1. 从头开始开发一个vue幻灯片组件

    首先新建项目vue init webpack projectName 安装依赖包npm i这些就不说了 接下来就是构建我们的swiper组件 因为我写的代码不规范, 通不过eslint的检测, 会频繁 ...

  2. c#蜘蛛

    C#写一个采集器 using System; using System.Collections.Generic; using System.Text; using System.Net; using ...

  3. Bugku | Easy_Re

    学到一个函数: _mm_storeu_si128((__m128i *)&v5, _mm_loadu_si128((const __m128i *)&xmmword_413E34)); ...

  4. Ant Design Pro (中后台系统)教程

    一.概念:https://pro.ant.design/docs/getting-started-cn(官方网站) 1.Ant Design Pro 是什么:  https://www.cnblogs ...

  5. 状压 DP:[USACO06NOV] Corn Fields,[USACO13NOV] No Change

    [USACO06NOV] Corn Fields (试题来源:Link ) 题目描述 Farmer John has purchased a lush new rectangular pasture ...

  6. 梅尔频谱(mel-spectrogram)提取,griffin_lim声码器【python代码分析】

    在语音分析,合成,转换中,第一步往往是提取语音特征参数.利用机器学习方法进行上述语音任务,常用到梅尔频谱.本文介绍从音频文件提取梅尔频谱,和从梅尔频谱变成音频波形. 从音频波形提取Mel频谱: 对音频 ...

  7. mybatis如何通过接口查找对应的mapper.xml及方法执行详解

    转:http://www.jb51.net/article/116402.htm 本文主要介绍的是关于mybatis通过接口查找对应mapper.xml及方法执行的相关内容,下面话不多说,来看看详细的 ...

  8. php使用curl抓取网页自动跳转问题处理

    问题分析: 请求抓取http://go.com数据: function curlGet($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, ...

  9. qbxt Day2 on 19-7-25

    qbxt Day2 on 19-7-25 --TGZCBY 上午 1. 矩阵乘法在图论上的应用 有的时候图论的转移方程可以用dp的方式转移 特别是两个数的乘积求和的时候 比如邻接矩阵中f[i][j]表 ...

  10. 嵌入式C语言4.1 C语言内存空间的使用-指针

    指针:就是内存资源的地址.门牌号的代名词 假如你所在的城市是一个内存(存储器),如果找到你家,就是通过你的家庭住址(指针)寻找,而你家里的摆设面积之类的就是内存的内容(指针指向的内容). 指针变量:存 ...