【题目分析】

这题好基啊。

先把分治树搞出来。然后每个节点两个堆。

第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离。

第二个堆保存分治树子树中所有儿子第一个堆的最大值。

建一个答案堆,表示所有节点第二个堆的最大值和次大值的和。

然后就是维护。

两点间距离用LCA转RMQ

调了4h,代码一度改到7k

【代码】

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxe 200005
#define maxn 100005
#define inf (0x3f3f3f3f)
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i) int h[maxe],to[maxe],ne[maxe],en=0,ban[maxn],n,m,rt,now,dst[maxn],Tree_rt,col[maxn],ans=-1,x,aim;
int b[maxn<<2],cnt=0,tag=0,pos[maxn],c[maxn<<2][20],_log[maxn<<2]; void add(int a,int b) {to[en]=b;ne[en]=h[a];h[a]=en++;}
struct Heap{
priority_queue <int> heap,del;
void Ins(int x){heap.push(x);}
void Del(int x){del.push(x);}
void Pop(){while (del.size()&&del.top()==heap.top()) del.pop(),heap.pop(); heap.pop();}
int Top(){while (del.size()&&del.top()==heap.top()) del.pop(),heap.pop(); return heap.top();}
int S_Top(){int tmp=Top(),ret;Pop();ret=Top();Ins(tmp);return ret; }
int Size(){return heap.size()-del.size();}
}s1[maxn],s2[maxn],lst; int mx[maxn],siz[maxn],size,fa[maxn];
char opt[11]; void dfs(int o,int fa)
{
if (!tag)b[++cnt]=o,pos[o]=cnt;
siz[o]=1;mx[o]=0;
for (int i=h[o];i>=0;i=ne[i])
if (!ban[to[i]]&&to[i]!=fa)
{
dfs(to[i],o);
if (!tag) b[++cnt]=o;
siz[o]+=siz[to[i]];
if (siz[to[i]]>mx[o]) mx[o]=siz[to[i]];
}
} void dfs_rt(int o,int fa)
{
if (max(mx[o],size-siz[o])<now) rt=o,now=max(mx[o],size-siz[o]);
for (int i=h[o];i>=0;i=ne[i])
if (!ban[to[i]]&&to[i]!=fa) dfs_rt(to[i],o);
} int lca(int a,int b)
{
int pa=pos[a],pb=pos[b];
if (pa>pb) swap(pa,pb);
int l=_log[pb-pa+1];
return min(c[pa][l],c[pb-(1<<l)+1][l]);
} int dist(int a,int b)
{return dst[a]+dst[b]-2*lca(a,b);} void dfs_add(int o,int fa)
{
s1[rt].Ins((dist(o,aim)));
for (int i=h[o];i>=0;i=ne[i])
if (!ban[to[i]]&&to[i]!=fa)
dfs_add(to[i],o);
} void Divide(int o,int fat)
{
int root;
dfs(o,-1); size=siz[o]; now=inf;
dfs_rt(o,-1); root=rt;
if (fat) fa[root]=fat;
ban[root]=1;
aim=fat;
dfs_add(root,-1);
s2[fat].Ins(s1[root].Top());
if (!col[root])
s2[root].Ins(0);
for (int i=h[root];i>=0;i=ne[i])
if (!ban[to[i]]) Divide(to[i],root);
if (s2[root].Size()>=2)
{
ans=max(ans,s2[root].Top()+s2[root].S_Top());
lst.Ins(s2[root].Top()+s2[root].S_Top());
}
} void dfs_dist(int o,int fat)
{
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=fat)
dst[to[i]]=dst[o]+1,dfs_dist(to[i],o);
} void Delete(int o)
{
if (s2[o].Size()>=2)
lst.Del(s2[o].Top()+s2[o].S_Top());
s2[o].Del(0);
if (s2[o].Size()>=2)
{
ans=max(ans,s2[o].Top()+s2[o].S_Top());
lst.Ins(s2[o].Top()+s2[o].S_Top());
}
if (s2[o].Size()>0) ans=max(ans,0);
int now=o;
while (now)
{
int fat=fa[now];
if (s2[fat].Size()>=2)
lst.Del(s2[fat].Top()+s2[fat].S_Top());
int tmp=s1[now].Top();
s1[now].Del(dist(o,fat));
if (s1[now].Size()==0||tmp!=s1[now].Top())
{
s2[fat].Del(tmp);
if (s1[now].Size()>0)
s2[fat].Ins(s1[now].Top());
}
if (s2[fat].Size()>=2)
{
ans=max(ans,s2[fat].Top()+s2[fat].S_Top());
lst.Ins(s2[fat].Top()+s2[fat].S_Top());
}
if (s2[fat].Size()>0) ans=max(ans,0);
now=fat;
}
} void Insert(int o)
{
if (s2[o].Size()>=2)
lst.Del(s2[o].Top()+s2[o].S_Top());
s2[o].Ins(0);
if (s2[o].Size()>=2)
{
ans=max(ans,s2[o].Top()+s2[o].S_Top());
lst.Ins(s2[o].Top()+s2[o].S_Top());
}
if (s2[o].Size()>0) ans=max(ans,0);
int now=o;
while (now)
{
int fat=fa[now];
if (s2[fat].Size()>=2)
lst.Del(s2[fat].Top()+s2[fat].S_Top());
int tmp,flag=0;
if (s1[now].Size()==0) flag=1;
else tmp=s1[now].Top();
s1[now].Ins(dist(o,fat));
if (flag||tmp!=s1[now].Top())
{
if (!flag)
s2[fat].Del(tmp);
s2[fat].Ins(s1[now].Top());
}
if (s2[fat].Size()>=2)
{
lst.Ins(s2[fat].Top()+s2[fat].S_Top());
ans=max(ans,s2[fat].Top()+s2[fat].S_Top());
}
if (s2[fat].Size()>0) ans=max(ans,0);
now=fat;
}
} int main()
{
memset(h,-1,sizeof h);
scanf("%d",&n);
F(i,1,n-1)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
tag=1;
dfs(1,-1);
now=inf; size=siz[1]; dfs_rt(1,-1); dfs_dist(rt,-1);
tag=0;
dfs(rt,-1);
tag=1;
F(i,1,cnt) c[i][0]=dst[b[i]]; F(i,2,cnt) _log[i]=_log[i>>1]+1;
F(j,1,_log[cnt])
for (int i=1;i+(1<<j)-1<=cnt;++i)
c[i][j]=min(c[i][j-1],c[i+(1<<j-1)][j-1]);
Tree_rt=rt;
Divide(1,0);
scanf("%d",&m);
F(i,1,m)
{
scanf("%s",opt);
switch(opt[0])
{
case 'G': if (lst.Size()) ans=max(ans,lst.Top());printf("%d\n",ans); break;
case 'C': scanf("%d",&x); ans=-1; if (!col[x]) Delete(x); else Insert(x); col[x]^=1; break;
}
}
}

  

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

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

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

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

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

  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. Windows上SVN服务器搭建【转】

    Subversion是优秀的版本控制工具,其具体的的优点和详细介绍,这里就不再多说.本文介绍Windows上 VisualSVN server 服务端和 TortoiseSVN客户端搭配使用: 现在S ...

  2. MS SQL生成数据库字典脚本

    开发一个项目时都会有一个蛋疼的问题——写数据库需求文档,然后根据这个文档来建数据库,如果后来需求改了,要改数据库还要改文档,有时忙着忙着就忘改了,导致文档是过期的.那么我们自己写个脚本在数据库运行直接 ...

  3. SQLServer同一实例下事务操作

    参考代码: 引用Dapper public bool OrderAdd2(User user, Order order) { string dbString = ConfigurationManage ...

  4. LibreOJ #103. 子串查找

    题目描述 这是一道模板题. 给定一个字符串 A AA 和一个字符串 B BB,求 B BB 在 A AA 中的出现次数. A AA 中不同位置出现的 B BB 可重叠. 输入格式 输入共两行,分别是字 ...

  5. 博客高亮代码及使用OpenLiveWriter修改之前博客

    简述:  最近查阅前辈资料的时候,看到写的博客很有条理,回头看下自己的乱做麻花,然后来时研究: 他们的代码看起来很漂亮然后我就查资料,在网页版上一直没法出来像他们的格式,后查资料看来的使用客户端工具才 ...

  6. MDI和在TabPage

    无奈的.net探索 MDI和在TabPage中增加Form分页? MDI(Multiple Document Interface)是一种在窗口中嵌套窗口的接口, 与之对应的是SDI(Single Do ...

  7. Python基础篇 -- if while 语句

    2.7 if语句 # 单纯if if 条件: 代码块 当条件成立,执行代码块 # 二选一 if 条件: 代码块1 else: 代码块2 #当条件为真,执行代码块1,否则执行代码块2 # 多选一 没有e ...

  8. struts2的多个文件上传

                成功效果图:                 上篇文章描述了单个文件的上传和配置,下面主要讲解下不同的地方: index.jsp <head> <script ...

  9. Bootstrap历练实例:点击激活的按钮

    <!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...

  10. Mac 录制视频,并转为GIF格式

    内容中包含 base64string 图片造成字符过多,拒绝显示