bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
好迷啊。。。感觉动态点分治就是个玄学,蜜汁把树的深度缩到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 捉迷藏 动态点分治学习的更多相关文章
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...
- BZOJ1095:[ZJOI2007]Hide 捉迷藏(动态点分治)
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
- 【bzoj1095】[ZJOI2007]Hide 捉迷藏 动态点分治+堆
题目描述 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这 ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆
写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ...
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏
简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ...
随机推荐
- BZOJ 1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居:队列 + multiset + 并查集【曼哈顿距离变形】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1604 题意: 平面直角坐标系中,有n个点(n <= 100000,坐标范围10^9) ...
- google IO大会
怎么参加一次 Google I/O?大概要多少预算? Google I/O(参加Goole I/O 是我的一个梦想,因为我是Google死忠,想亲自去Google总部看看,所以想知道这些) 费用构成: ...
- 常见css兼容问题
链接的虚线框问题 <!-- html --> <a class="noDashedBox" href="#"><img src=& ...
- struts2 validate手动验证
我们前面学习struts2知道,struts2通过拦截器实现了一些验证操作. 比如,如果是不能转换的类型在action中接受的话会跳转到错误页面,错误信息中会包含对应的错误信息,例如: 首先我们了解一 ...
- 集训Day2
雅礼集训2017Day2 T1 给你一个水箱,水箱里有n-1个挡板,水遵循物理定律 给你m个条件,表示第i个格子上面y+1高度的地方有或没有水 现在给你无限的水从任意地方往下倒,问最多满足多少条件 n ...
- node.js Web应用框架Express入门指南
node.js Web应用框架Express入门指南 作者: 字体:[增加 减小] 类型:转载 时间:2014-05-28 我要评论 这篇文章主要介绍了node.js Web应用框架Express入门 ...
- 数据结构与算法(4)----->链表、二分搜索
1. 链表的基本概念 链表和数组一样都是一种线性结构; 数组是一段连续的存储空间; 链表空间不一定保证连续,是临时分配的; 链表的分类 按方向: 单链表:每个节点只能通过next指针指向下一个节点; ...
- Mesos以及Marathon安装总结
安装了将近一周的环境了,终于把Mesos以及Marathon给安装上了,我指的离线安装. 策略1: 严格的按照官网的流程: http://mesos.apache.org/gettingstarted ...
- bzoj 1119 [POI2009] SLO & bzoj 1697 牛排序 —— 置换+贪心
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1119 https://www.lydsy.com/JudgeOnline/problem.p ...
- idea 调试技巧1
1 多线程调试 开发过多线程应用的朋友应该有体会,有些时候,为了观察多个线程间变量的不同状态,以及锁的获取等,就会想到在代码里加个断点debug一下. 在IDE里断点停下来的时候,可以切换到另外的线程 ...