好迷啊。。。感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn

(静态)点分治大概是递归的时候分类讨论:

  1.答案经过当前点,暴力(雾)算

  2.答案不经过当前点,继续递归

由于原树可以长的奇形怪状(菊花啊、、链啊、、扫把啊、、)这就导致各种方法都会被卡

于是通过每次找重心保证最大深度

动态怎么解决呢?

不妨考虑线段树是二分的固态版本(只可意会),那么我们把每次找到的重心固定下来长成一棵树就可以把点分治凝固(不可言传)

原来点分治该维护什么现在就维护什么。。。

(事实上我并没有写过静态点分治。。。好气啊╮(╯▽╰)╭)

我居然一度认为新建的树的节点要连到所在子树外一定要经过该子树的根。。。太思博了

实现细节:

  1.有一个带删堆,直接拉了板子(拉了才知道实现那么简单,本来以为手打)

  2.lca以前习惯rmq(复杂度优异就是自信),现在改成倍增了(可能是之前写了个长链剖分的缘故)

 #include<bits/stdc++.h>
using namespace std;
const int Mn=;
int cnt=,h[Mn],n,m,vst[Mn],maxx,tg,s[Mn],sz,prt[Mn];
int d[Mn],p[Mn][],co[Mn];
struct Priority_Queue{
priority_queue<int> q,del;
void push(int x)
{q.push(x);}
void erase(int x){del.push(x);}
int top()
{
while(del.size()&&del.top()==q.top())
{del.pop();q.pop();}
return q.top();
}
void Pop()
{
while(del.size()&&del.top()==q.top())
del.pop(),q.pop();
q.pop();
}
int sec_top()
{
int tmp=top();Pop();
int se=top();push(tmp);
return se;
}
int size()
{
return q.size()-del.size();
}
}c[Mn],f[Mn],ans;
struct Edge{int to,next;}w[Mn*];
void add(int x,int y)
{w[++cnt]=(Edge){y,h[x]};h[x]=cnt;}
void build(int x,int fa)
{
p[x][]=fa;d[x]=d[fa]+;
for(int i=;p[x][i-];i++)
p[x][i]=p[p[x][i-]][i-];
for(int i=h[x];i;i=w[i].next)
if(w[i].to!=fa)
build(w[i].to,x);
}
void Insert(Priority_Queue &s){
if(s.size()>)ans.push(s.top()+s.sec_top());
}
void Erase(Priority_Queue &s){
if(s.size()>)ans.erase(s.top()+s.sec_top());
}
void DP(int x,int fa)
{
int j,y;s[x]=;
for(j=h[x];j;j=w[j].next)
{
y=w[j].to;
if(y==fa||vst[y])continue;
DP(y,x);
s[x]+=s[y];
}
}
void Biggest(int x,int fa){
int j,y,mx=;
for(j=h[x];j;j=w[j].next){
y=w[j].to;
if(y==fa||vst[y])continue;
Biggest(y,x);
mx=max(mx,s[y]);
}
if(maxx>max(mx,sz-s[x])){
maxx=max(mx,sz-s[x]);
tg=x;
}
}
int gg(int x)//get G
{
maxx=n+;tg=;
DP(x,);
sz=s[x];
Biggest(x,);
return tg;
}
int LCA(int x,int y){
int j;
if(d[x]<d[y])swap(x,y);
for(j=;j>=;j--)
if(d[p[x][j]]>=d[y])x=p[x][j];
if(x==y)return x;
for(j=;j>=;j--)
if(p[x][j]!=p[y][j])
{x=p[x][j];y=p[y][j];}
return p[x][];
}
int Dis(int x,int y){return d[x]+d[y]-*d[LCA(x,y)];}
void work(int x,int fa,int Gra){
int j,y;
f[Gra].push(Dis(x,prt[Gra]));
for(j=h[x];j;j=w[j].next){
y=w[j].to;
if(y==fa||vst[y])continue;
work(y,x,Gra);
}
}
int mzz(int x,int fa)
{
int j,y,G,Gy;
G=gg(x);prt[G]=fa;
work(G,,G);
vst[G]=;
c[G].push();
for(j=h[G];j;j=w[j].next)
{
y=w[j].to;
if(!vst[y]){
Gy=mzz(y,G);
c[G].push(f[Gy].top());
}
}
Insert(c[G]);
return G;
}
void Light(int x){
Erase(c[x]);
c[x].erase();
Insert(c[x]);
for(int y=x;prt[y];y=prt[y]){
Erase(c[prt[y]]);
if(f[y].size())c[prt[y]].erase(f[y].top());
f[y].erase(Dis(x,prt[y]));
if(f[y].size())c[prt[y]].push(f[y].top());
Insert(c[prt[y]]);
}
}
void LiOut(int x){
Erase(c[x]);
c[x].push();
Insert(c[x]);
for(int y=x;prt[y];y=prt[y]){
Erase(c[prt[y]]);
if(f[y].size())c[prt[y]].erase(f[y].top());
f[y].push(Dis(x,prt[y]));
if(f[y].size())c[prt[y]].push(f[y].top());
Insert(c[prt[y]]);
}
}
void solve(){
int i,x;char ch[];
cnt=n;
scanf("%d",&m);
for(i=;i<=m;i++){
scanf("%s",ch);
if(ch[]=='G'){
if(cnt<=)printf("%d\n",cnt-);
else printf("%d\n",ans.top());
}
else{
scanf("%d",&x);
if(!co[x]){cnt--;Light(x);co[x]=;}
else{cnt++;LiOut(x);co[x]=;}
}
}
}
int main()
{
scanf("%d",&n);int x,y;
for(int i=;i<n;i++)
scanf("%d%d",&x,&y),
add(x,y),add(y,x);
build(,);mzz(,);
solve();
return ;
}

bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 纯CSS3左右滑动开关按钮

    纯CSS3特效左右滑动开关按钮是一款非常酷的CSS3 3D开关按钮,点击按钮可以左右滑动,就像开关打开闭合一样的效果. http://www.huiyi8.com/sc/10626.html

  2. 浅析linux 下shell命令执行和守护进程

    执行shell脚本有以下几种方式 1.相对路径方式,需先cd到脚本路径下 [root@banking tmp]# cd /tmp [root@banking tmp]# ./ceshi.sh 脚本执行 ...

  3. bzoj 3522: Hotel dfs

    题目大意 在无边权树上求三个点,使两两点的距离等.求方案数\((n\leq 5000)\) 题解 我们知道三个点在树上的关系只有两种 三点共链 三点不共连 (这不是废话吗) 我们发现三点共链肯定不满足 ...

  4. 运维程序】简单的命令控制器(支持定时命令执行、重复定时任务命令和进程管理,开发这个小程序主要是为了方便管理服务进程)【个人github项目】

    一.前言: command-controller 一个运维程序,简单的命令控制器(支持定时命令执行和重复定时命令,开发这个程序主要是为了方便管理服务进程) 本来是要用python做的,但是之前做ffm ...

  5. python爬虫知识点总结(十)分析Ajax请求并抓取今日头条街拍美图

    一.流程框架

  6. 程序设计中的计算复用(Computational Reuse)

    从斐波那契数列说起 我想几乎每一个程序员对斐波那契(Fibonacci)数列都不会陌生,在很多教科书或文章中涉及到递归或计算复杂性的地方都会将计算斐波那契数列的程序作为经典示例.如果现在让你以最快的速 ...

  7. WPF ValidationRule 触发ErrorTemplate 的注意事项

    ValidationRule 验证时, 当验证失败后,再次验证成功, errorTemplate 还是触发, 不会被清掉. 因此需要主动调用 Validation.ClearInvalid(dtpTe ...

  8. fabric添加多主机ssh互信

    最近折腾fabric,把服务器ssh互信用fabric写了一遍,单向互信,master可以无密码访问client,具体如下: 执行:fab  -f ./copyrsa.py allsshkey 即可, ...

  9. 五 python 发送邮件

    需求: 系统中使用一个邮箱(这里用QQ)给其他邮箱发消息,用python完成,步骤如下: 1: 开启QQ邮箱的SMTP服务.设置-> 账号 2: 开启邮箱服务:这个需要手机验证,最后会给你一个授 ...

  10. go http 下载视频(TS码流文件)(推荐一个网站学习 go example)

    视频  http下载代码 dn.go(注意:代码很ugly,没怎么花时间) 总体感觉特别简单,网上看了下 net/http ,io这2个库的使用, 几分钟就写完了,感觉cpp 在做工具这块 开发效率的 ...