好迷啊。。。感觉动态点分治就是个玄学,蜜汁把树的深度缩到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. RQNOJ 328 炮兵阵地:状压dp

    题目链接:https://www.rqnoj.cn/problem/328 题意: 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队. 一个N*M的地图由N行M列组成(N≤100,M≤10), ...

  2. tensorflow 线性回归 iris

    线性拟合

  3. Zabbix监控华为交换机

    一.    监控交换机首先要在交换机开通snmp协议. 有两种方式开通,web界面,及交换机的配置界面 Web界面开通: 交换机配置界面 有web界面的,使用web界面相对简单,本项目就是用web界面 ...

  4. Java IO(输入输出)

    1. System.out.System.in System 内部: public final static InputStream in = null; public final static Pr ...

  5. rman理论(一)

    1) 快照控制文件:开始备份后,RMAN 需要这些信息在备份操作期间保持一致,也就是说RMAN需要一个读取一致的控制文件视图. 除非RMAN 在备份持续时间内锁定控制文件,否则数据库会不断更新控制文件 ...

  6. mysql错误-修改mysql.sock位置

    在Mysql下有时候会出现mysql.sock位置错误,导致无法链接数据库. mac下报错的时候: 首先修改my.cnf 位置在/etc/my.cnf下,假如没有的话,去/usr/locate/mys ...

  7. PHP函数---$_Get()和$_Post()的用法

    一.$_Get()和$_Post()函数是用来传值的,即对应两种提交表单的方法,get和post. 二.$_Get方法 (1)获取通过URL的传值 Example 1 新建两个PHP文件,1.php, ...

  8. zk 10之:Curator之三:服务的注册及发现

    Service Discovery 我们通常在调用服务的时候,需要知道服务的地址,端口,或者其他一些信息,通常情况下,我们是把他们写到程序里面,但是随着服务越来越多,维护起来也越来越费劲,更重要的是, ...

  9. 托管C++——在C#中使用C++

    下面就用一个完整的实例来详细说明怎样用托管C++封装一个C++类以提供给C#使用. 现有一个Detector类需要使用,首先,要创建一个托管C++的DLL工程DAADll,然后在里面添加下面的代码: ...

  10. 条款32:确定你的public继承塑模出is-a的关系

    Make sure public inheritance models "is –a " 如果令clsss D 以public的形式继承class B,你便是告诉编译器说,每一个类 ...