好迷啊。。。感觉动态点分治就是个玄学,蜜汁把树的深度缩到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. the art of seo(chapter eight)

    How Social Media and User Data Play a Role in Search Results and Rankings ***Correlation Between Soc ...

  2. Java的访问权限修饰符

    default或者friendly表示默认的访问权限修饰符.

  3. MD5算法的简单编写

    package com.t_09; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; ...

  4. android如何查看网卡名和ip

    我们知道,在windows下查看ip地址用ipconfig,在Linux下查看ip地址用ifconfig.今天在使用android查看的时候ifconfig却不管用: 查找网上资料发现,原来默认ifc ...

  5. 1131 Subway Map(30 分)

    In the big cities, the subway systems always look so complex to the visitors. To give you some sense ...

  6. The Django Book 2.0--中文版

    Table of contents 2.0, English -> Chinese 第一章:介紹Django阅读 01 第二章 入门阅读 02 第三章 视图和URL配置阅读 03 第四章:模版阅 ...

  7. 发个IOCP的C++例子

    IOCP的c++例子 IOCP这个东西连续关注了将近3年的时间,这个代码从哪里找到的已经忘了,下面是作者的信息.感谢他提供的代码! /*++ Copyright (c) 2004 模块名: iomod ...

  8. CF1076E:Vasya and a Tree

    浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://codeforces.com/problemset/prob ...

  9. KCF+Opencv3.0+Cmake+Win10 测试

    配置 需要的文件下载 安装CMake,安装opencv3.0.0 在KCFcpp-master 目录下新建一个文件夹,命名为build 打开CMake-GUI配置如下: 点击Configure,编译器 ...

  10. python基础知识-数字

    数字分为: 整数(int) 长整型(long) 浮点型(float) 一,整数 整数(int):即不带小数点的数字,如 12 ,45 ,0 ,3 #!/usr/bin/env python class ...