1095: [ZJOI2007]Hide 捉迷藏
题意:给定一棵树,每个节点可以变成黑白两色。一开始所有节点都是黑色,操作可将点颜色改变,询问当前情况下距离最远的两个黑点的距离。
动态树分治。一开始想的是对于每个节点维护主大和次大,后来发现这实在是太NAIVE了。实际上,正解是这样的:
对于每个点,维护两个堆(接下来说的都是点分树上的节点):第一个堆,该点子树到该点父亲的距离,第二个堆,该点直接儿子的第一个堆的堆顶元素。
然后我们再开一个全局堆,即答案堆,维护所有第二个堆最大和次大之和。每次询问只要把堆顶元素拿出来就可以了。
为什么空间开的下呢?这个道理和震波那道题是一样的,考虑点分治的时间复杂度,每个点最大堆空间开到的就是该点子树大小,总和是nlogn的,完全开的下。
怎么修改呢,暴力爬树高啊,点分树不就是这一点树高稳定log最好吗!
维护3个堆的过程特别繁琐,写的时候写了一个上午。。。就为了那几个if。。
最后被自己模拟的堆坑了一发。。改到现在才过
上代码
#include<bits/stdc++.h>
using namespace std;
#define N 100005
#define INF 1e9
inline int read(){
int x=,f=; char a=getchar();
while(a<'' || a>'') {if(a=='') f=-; a=getchar();}
while(a>='' && a<='') x=x*+a-'',a=getchar();
return x*f;
}
int n,q,head[N],s[N],cnt,f[N],rt,sz,dep[N],fa[N][],dis[N][],now;
char ch[]; bool vis[N],on[N];
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(); if(A.size()) return A.top(); else return -INF;}
int size() {return A.size()-B.size();}
int s_top(){ if(size()<) return -INF;
while(B.size()&&A.top()==B.top()) A.pop(),B.pop();
int t=A.top(),ret; A.pop();
while(B.size()&&A.top()==B.top()) A.pop(),B.pop();
ret=A.top(); A.push(t);
return ret;
}
}C,A[N],B[N];
struct edges{
int to,next;
}e[*N];
void insert(){
int u=read(),v=read();
e[cnt]=(edges){v,head[u]};head[u]=cnt++;
e[cnt]=(edges){u,head[v]};head[v]=cnt++;
}
void getroot(int x,int p){
s[x]=; f[x]=;
for(int i=head[x];i>=;i=e[i].next){
if(vis[e[i].to] || p==e[i].to) continue;
getroot(e[i].to,x); s[x]+=s[e[i].to];
f[x]=max(f[x],s[e[i].to]);
}
f[x]=max(f[x],sz-s[x]);
if(f[rt]>f[x]) rt=x;
}
void getship(int x,int anc,int p,int d){
for(int v,i=head[x];i>=;i=e[i].next){
v=e[i].to;
if(vis[v] || p==v) continue;
fa[v][++dep[v]]=anc; dis[v][dep[v]]=d; getship(v,anc,x,d+);
}
}
void buildtree(int x){
vis[x]=; getship(x,x,,); int all=sz;
for(int i=head[x];i>=;i=e[i].next){
if(vis[e[i].to]) continue;
if(s[e[i].to]>s[x]) s[e[i].to]=all-s[x]; sz=s[e[i].to];
rt=; getroot(e[i].to,x); buildtree(rt);
}
}
void turn_off(int x){
B[x].push();
if(B[x].size()==) C.push(B[x].top());
for(int t,pre,i=dep[x];i>;i--){
if(!A[fa[x][i]].size()){
A[fa[x][i]].push(dis[x][i-]);
pre=B[fa[x][i-]].top()+B[fa[x][i-]].s_top();
B[fa[x][i-]].push(dis[x][i-]);
if(pre> && pre==B[fa[x][i-]].top()+B[fa[x][i-]].s_top()) continue;
if(pre> && pre!=B[fa[x][i-]].top()+B[fa[x][i-]].s_top())
C.erase(pre),C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
else if(B[fa[x][i-]].top()+B[fa[x][i-]].s_top()>) C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
}else{
t=A[fa[x][i]].top(); A[fa[x][i]].push(dis[x][i-]);
if(t<dis[x][i-]){
pre=B[fa[x][i-]].top()+B[fa[x][i-]].s_top();
B[fa[x][i-]].erase(t); B[fa[x][i-]].push(dis[x][i-]);
if(pre> && pre!=B[fa[x][i-]].top()+B[fa[x][i-]].s_top())
C.erase(pre),C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
}
}
}
}
void turn_on(int x){
B[x].erase();
if(B[x].size()==) C.erase(B[x].top());
for(int t,pre,i=dep[x];i>;i--){
A[fa[x][i]].erase(dis[x][i-]);
if(A[fa[x][i]].top()<dis[x][i-]) {
pre=B[fa[x][i-]].top()+B[fa[x][i-]].s_top();
B[fa[x][i-]].erase(dis[x][i-]);
if(A[fa[x][i]].size()) B[fa[x][i-]].push(A[fa[x][i]].top());
if(pre>) {
if(pre==B[fa[x][i-]].top()+B[fa[x][i-]].s_top()) continue;
C.erase(pre);
if(B[fa[x][i-]].size()>)
C.push(B[fa[x][i-]].top()+B[fa[x][i-]].s_top());
}
}
}
}
inline void change(int x){
if(!on[x]) turn_on(x);
else turn_off(x);
on[x]^=;
if(on[x]) now++;
else now--;
}
int main(){
n=read(); memset(head,-,sizeof(head));
for(int i=;i<n;i++) insert();
f[]=INF; sz=n; getroot(,); buildtree(rt);
for(int i=;i<=n;i++) fa[i][++dep[i]]=i,turn_off(i);
q=read();
while(q--){
scanf("%s",ch);
if(ch[]=='G') {
if(now==n) puts("-1");
else printf("%d\n",max(C.top(),));
}
else change(read());
}
return ;
}
1095: [ZJOI2007]Hide 捉迷藏的更多相关文章
- 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)
1095: [ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏 ...
- 【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏
Description 一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离. Sol 动态点分治. 动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的... ...
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1095 [题意] 给定一棵树,树上颜色或白或黑而且可以更改,多个询问求最远黑点之间的距离 ...
- 洛谷.4115.Qtree4/BZOJ.1095.[ZJOI2007]Hide捉迷藏(动态点分治 Heap)
题目链接 洛谷 SPOJ BZOJ1095(简化版) 将每次Solve的重心root连起来,会形成一个深度为logn的树,就叫它点分树吧.. 我们对每个root维护两个东西: 它管辖的子树中所有白点到 ...
- 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树
[题目]BZOJ 1095 [题意]给定n个黑白点的树,初始全为黑点,Q次操作翻转一个点的颜色,或询问最远的两个黑点的距离,\(n \leq 10^5,Q \leq 5*10^5\). [算法]括号序 ...
- 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ...
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ...
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏 ——动态点分治
[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ...
随机推荐
- .net程序员的学习计划
.net程序员的学习计划 与其说是计划,不如说是抄来的课程表.基于最近老大要求写一份一年的职业规划.我是一个向来没什么规划的人,不是职场规划,就连平时的规划都没有,基本上就是有什么任务就去完成.回想起 ...
- 学习JAVA的第一天。
今天上了JAVA的第一堂课,对<JAVA 面向对象编程>小看了2个单元,感觉难度还行,在自己的理解范围,应该都是基础,记得以前在学校里也听老师讲过课是根本没有用心. 相信自己一定能学好,J ...
- ruby基础语法
首发:个人博客,更新&纠错&回复 学不同语言,常将它们的基础语法搞混,例如if后面有没有(),后面是then还是:还是{,结尾是end还是}. 这种事情毫无技术含量又毫无乐趣可言,但极 ...
- Asp.net MVC进入请求管道的过程
Asp.net MVC进入请求管道的过程 Asp.Net MVC 跟AspNet 入口解释 Asp.Net MVC请求处理过程 mvc 请求模型 mvc的原理 mvc模型 NewMVCPipleLin ...
- 谈谈JDK线程的伪唤醒
在JDK的官方的wait()方法的注释中明确表示线程可能被"虚假唤醒",JDK也明确推荐使用while来判断状态信息.那么这种情况的发生的可能性有多大呢? 使用生产者消费者模型来说 ...
- 《Unix网络编程》卷一(简介TCP/IP、基础套接字编程)
通常说函数返回某个错误值,实际上是函数返回值为-1,而全局变量errno被置为指定的常值(即称函数返回这个错误值). exit终止进程,Unix在一个进程终止时总是关闭该进程所有打开的描述符. TCP ...
- Script 语言的简单练习题 乘法口诀
<script>for(var i=1;i<=9;i++){ for(var k=1;k<=i;k++) { document.write(k+"x"+i+ ...
- 两个img之间出现间隙的解决方法
今天写了个小页面,发现了一个问题,两个包在a标签里的img之间总是有间隙,不能挨在一起,最后在同事的帮助下,找到解决的办法是,设置img的基线,css代码如下: img{vertical-align: ...
- Android-Universal-Image-Loader的缓存处理机制
讲到缓存,平时流水线上的码农一定觉得这是一个高大上的东西.看过网上各种讲缓存原理的文章,总感觉那些文章讲的就是玩具,能用吗?这次我将带你一起看过UIL这个国内外大牛都追捧的图片缓存类库的缓存处理机制. ...
- MVC中Razor的使用 及路径问题
语法: @ 可以编写一条C#语句@{} 可以编写一组C#语句@: 将文字内容直接输出到页面上去@() 在一句中将一段C#代码包括起来,证明这一句完整的C#代码 引用命名空间:@using 空间名称 H ...