【BZOJ1095】[ZJOI2007]Hide 捉迷藏

Description

  捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange) i 改变第i个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。

Input

  第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。接下来N-1行每行两个整数a, b,表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如上文所示。

Output

  对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关着灯的,输出0;若所有房间的灯都开着,输出-1。

Sample Input

8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G

Sample Output

4
3
3
4

HINT

对于100%的数据, N ≤100000, M ≤500000。

题解:将点分治时经过的所有节点取出来,按分治的先后顺序构成一棵树,叫做点分树,它的树高是logn的,我们就可以利用这个性质来搞一些事情,这就叫做动态点分治。(个人理解,勿喷)

然后呢,本题要求的是虚树的直径,那么我们沿用树形DP的思想,维护每个子树中深度的最大和次大值,我们开一个堆A即可。但是要求最大和次大值不能再同一个儿子的子树中,那么我们就需要对于每个儿子都维护一个堆B,用堆B来更新父亲的堆A。最后为了统计答案,我们再开一个全局的堆C即可。

所以本题一共用了3个堆。

B:维护每个点的子树中(所说的子树全是指分治结构的子树)所有点到该点的父亲的距离。
A:维护每个点的所有儿子(分治结构的儿子)的B的堆顶。
C:维护所有堆A的最大值+次大值。

可删除的堆怎么写?开两个堆,一个代表所有元素,一个代表已经被删除的元素就行了。

鉴于BZ老爷机的速度,我们求两点间还是用RMQ-LCA吧~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int maxn=100010;
int n,m,mn,rt,tot,cnt,sum;
int to[maxn<<1],next[maxn<<1],head[maxn],fa[maxn],dep[maxn],pos[maxn];
int md[18][maxn<<1],Log[maxn<<1],siz[maxn],q[maxn];
bool light[maxn],vis[maxn];
struct heap
{
priority_queue<int> A,B;
void push(int x) {A.push(x);}
void erase(int x) {B.push(x);}
void pop()
{
while(B.size()&&A.top()==B.top()) A.pop(),B.pop();
A.pop();
}
int top()
{
while(B.size()&&A.top()==B.top()) A.pop(),B.pop();
return !A.size()?0:A.top();
}
int top2()
{
if(size()<2) return 0;
int x=top(); pop();
int y=top(); push(x);
return y;
}
int size() {return A.size()-B.size();}
}p1[maxn],p2[maxn],p;
char str[10];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int lca(int a,int b)
{
a=pos[a],b=pos[b];
if(a>b) swap(a,b);
int k=Log[b-a+1];
return min(md[k][a],md[k][b-(1<<k)+1]);
}
int dis(int a,int b)
{
return dep[a]+dep[b]-2*lca(a,b);
}
void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void getr(int x,int fa)
{
siz[x]=1;
int tmp=0,i;
for(i=head[x];i!=-1;i=next[i]) if(to[i]!=fa&&!vis[to[i]])
getr(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]);
tmp=max(tmp,tot-siz[x]);
if(tmp<mn) mn=tmp,rt=x;
}
void solve(int x)
{
vis[x]=1,q[++q[0]]=x;
for(int i=head[x];i!=-1;i=next[i]) if(!vis[to[i]]) tot=siz[to[i]],mn=1<<30,getr(to[i],x),fa[rt]=x,solve(rt);
}
void dfs(int x)
{
md[0][++pos[0]]=dep[x],pos[x]=pos[0];
for(int i=head[x];i!=-1;i=next[i]) if(!dep[to[i]]) dep[to[i]]=dep[x]+1,dfs(to[i]),md[0][++pos[0]]=dep[x];
}
void turnoff(int x,int y)
{
if(x==y)
{
p2[x].push(0);
if(p2[x].size()==2) p.push(p2[x].top());
}
if(!fa[x]) return ;
int f=fa[x],d=dis(f,y),tp=p1[x].top();
p1[x].push(d);
if(d>tp)
{
int mx=p2[f].top()+p2[f].top2(),sz=p2[f].size();
if(tp) p2[f].erase(tp);
p2[f].push(d);
int nx=p2[f].top()+p2[f].top2();
if(nx>mx)
{
if(sz>=2) p.erase(mx);
if(p2[f].size()>=2) p.push(nx);
}
}
turnoff(f,y);
}
void turnon(int x,int y)
{
if(x==y)
{
if(p2[x].size()==2) p.erase(p2[x].top());
p2[x].erase(0);
}
if(!fa[x]) return ;
int f=fa[x],d=dis(f,y);
p1[x].erase(d);
int tp=p1[x].top();
if(d>tp)
{
int mx=p2[f].top()+p2[f].top2(),sz=p2[f].size();
p2[f].erase(d);
if(tp) p2[f].push(tp);
int nx=p2[f].top()+p2[f].top2();
if(nx<mx)
{
if(sz>=2) p.erase(mx);
if(p2[f].size()>=2) p.push(nx);
}
}
turnon(f,y);
}
int main()
{
n=rd();
int i,j,a,b;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),add(a,b),add(b,a);
dep[1]=1,dfs(1);
for(i=2;i<=2*n-1;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=2*n-1;j++)
for(i=1;i+(1<<j)-1<=2*n-1;i++)
md[j][i]=min(md[j-1][i],md[j-1][i+(1<<(j-1))]);
tot=n,mn=1<<30,getr(1,0),solve(rt);
for(i=1;i<=n;i++) turnoff(i,i);
m=rd(),sum=n;
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='G')
{
if(sum>=2) printf("%d\n",p.top());
else if(sum==1) printf("0\n");
else printf("-1\n");
}
else
{
a=rd();
if(light[a]) sum++,light[a]=0,turnoff(a,a);
else sum--,light[a]=1,turnon(a,a);
}
}
return 0;
}//8 1 2 2 3 3 4 3 5 3 6 6 7 6 8 7 G C 1 G C 2 G C 1 G

【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆的更多相关文章

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

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

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

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

  3. bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习

    好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...

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

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

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

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

  6. bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治

    这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...

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

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

  8. bzoj 1095 Hide 捉迷藏 - 动态点分治 -堆

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

  9. [bzoj1095][ZJOI2007]Hide 捉迷藏——线段树+括号序列

    题目大意 给定一棵所有点初始值为黑的无权树,你需要支援两种操作: 把一个点的颜色反转 统计最远黑色点对. 题解 本题是一个树上的结构.对于树上的结构,我们可以采用点分治.树链剖分等方法处理,这个题用了 ...

随机推荐

  1. 在Linux 双机下自己手动实现浮动ip技术

    两台Linux服务器,一台为主机(IP:124.158.26.30)对外提供了一定的网络服务,另一台从机(IP:124.158.26.31)能提供相同的服务,但ip地址没有对外部公开客户端连接的都是1 ...

  2. JDK1.5新特性:

    1.自动装箱与拆箱: 自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中. 自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动地提取出来,没必要再去调用i ...

  3. ListView设置某一项item的文本居中

    使用ListView和volley写了一个使用网络获取天气的demo ListView中Item的文本模式都是左侧对齐 我这边需要一些标题文本居中对齐 网上也找不到示例,不过找到了getView这个函 ...

  4. OpenSSL使用1(用OpenSSL生成自签名证书在IIS上搭建Https站点)(用于iOS的https访问)

    前提: 先安装openssl,安装有两种方式,第一种直接下载安装包,装上就可运行:第二种可以自己下载源码,自己编译.这里推荐第一种. 安装包:http://slproweb.com/products/ ...

  5. Windows Server 2008 IE 无法调整安全级别

    开始”/“程序”/“管理工具”/“服务器管理器”命令,在弹出的服务器管理器窗口中,找到“安全信息”设置项,单击其中的“配置IE ESC”选项,打开如下图所示的IE增强安全配置窗口.

  6. linux基础学习7

      Linux 的开机流程分析 1. 加载 BIOS 的硬件信息与进行自我测试,并依据设定取得第一个可开机的装置: 2. 读取并执行第一个开机装置内 MBR 的 boot Loader (亦即是 gr ...

  7. 比JSONKit还要快的第三方JSON解析器NextiveJson

    这款比JSONKit还好用,效率跟iOS5原生的差不多,不过解析后对内存的释放比原生的要多.所以推荐 https://github.com/nextive/NextiveJson 顺便提一下解析XML ...

  8. 【spring boot】6.idea下springboot打包成jar包和war包,并且可以在外部tomcat下运行访问到

    接着上一章走呗:http://www.cnblogs.com/sxdcgaq8080/p/7712874.html 然后声明一点,下面打包的过程中,scope一直都是使用默认的范围 <!--用于 ...

  9. 【前端阅读】——《活用PHP、MySQL建构Web世界》摘记之设计技巧

    二.设计技巧 Programming的习惯因人而异,这里只提供一些经验,可以参考. 1.利用Include模块化你的程序代码 Include函数基本上说:就像是把另一个文件(HTML或者PHP程序)读 ...

  10. C#反射获取属性值和设置属性值

    /// /// 获取类中的属性值 /// public string GetModelValue(string FieldName, object obj) { try { Type Ts = obj ...