Time Limit: 4000 ms   Memory Limit: 256 MB

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。


Solution

  题意是有一棵黑白点树,要支持两种操作:将一个点黑白反色,或者查询任意两个黑点的距离的最大值。

  用动态树分治来做:先试着在每一个重心上,维护经过这个重心的两个黑点距离最大值。

  看看能不能维护重心$u$的管辖范围内每个黑点到$u$的距离最大值和次大值,然后加起来就是答案。用一个堆就可以实现,但是发现不好处理两个黑点处在同一子树的问题。

  如果我们能把子树的信息相互独立就好:对于$u$的每一个子树$v$,将$v$子树内所有点到$u$的距离放进一个堆$C_v$里(为了方便,将$C_v$记录在$v$子树的重心$v'$上)。那么对于$u$的每一个$v$子树,将其$C_v$的最大值再组成一个堆$B_u$。因为所有值都互相独立,所以能保证不会出现同一子树情况,因此$B_u$的最大值加上次大值就是经过这个重心的答案。

  对于所有的重心$u$,将$B_u$的最大值加上次大值,扔进一个全局堆$A$中,每次查询输出堆顶即可(如果出现题目描述特殊情况直接输出0或-1)。

  

  进行修改操作时,在点分树上向上迭代。若当前重心为$u$,其父亲为$f$,先用$B_f$的最大值加次大值来删$A$,再用$C_u$的堆顶删$B_f$,更新$C_u$,然后用$C_u$的堆顶更新$B_f$,最后用$B_f$的最大值加次大值更新$A$。  

可按权值删除的堆:

  这道题中所使用的堆,除了加入一个权值之外,有可能要求从堆中删除一个值为$x$的元素。

  可以自己实现一个可删堆:其中包含一个主堆$a$和删堆$b$。

  增加元素时推入$a$;删除值为$x$的元素时,将$x$推入$b$;进行提取操作(pop();top();)时,如果$a$和$b$堆顶相同则弹出,直到$a$和$b$堆顶不同或$b$为空为止。这样就巧妙地实现了可删堆。

Tips:

  1. 如果一个重心$u$自己是黑点,那么应该在$B_u$中添加一个值为0的元素(这适用于B堆将两条连拼接起来的本质);否则$B_u$内不应有值为$0$的元素。

  2. 如果一个重心$u$的$B_u$的集合大小小于2,这意味着$u$子树内只用一个黑点。那么不要用$B_u$更新$A$,$A$中不应该存在$B_u$对应的元素,因为此时根本不能组成路径。

  3. 一定要注意优化!改变一个点的状态时,用可用的条件先判断,避免过多的堆操作(真坑爹)。如新加入$C$的值,可与$C$原先堆顶的大小进行判断,如果比原堆顶大,再更新$B$和$A$,否则可以不用进行接下来的操作;删除$C$中的一个值,先判断该值是否和$C$的堆顶相同,如果是才更新$B$和$A$,否则不用操作。


#include <cstdio>
#include <queue>
using namespace std;
const int N=,Bas=,INF=;
int n,q,h[N],tot,cnt;
int sum,nrt,nval,size[N],cut[N];
int dep[N],pre[N][Bas];
int fa[N];
int st[N];
struct Edge{int v,next;}g[N*];
struct Heap{
priority_queue<int> a,b;
int size(){return a.size()-b.size();}
void push(int x){if(x!=-) a.push(x);}
void erase(int x){if(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()?a.top():-;
}
int sop(){
if(size()<) return ;
int x=top(); pop();
int y=top(); push(x);
return y;
}
int count(){
int sz=size(),x=top(),y=sop();
if(sz<) return -;
else return x+y;
}
}a,b[N],c[N];
inline int rd(){
char c;
int x=;
while((c=getchar())<''||c>'');
x=c-'';
while(''<=(c=getchar())&&c<='') x=x*+c-'';
return x;
}
inline void swap(int &x,int &y){int t=x;x=y;y=t;}
inline void addEdge(int u,int v){
g[++tot].v=v; g[tot].next=h[u]; h[u]=tot;
g[++tot].v=u; g[tot].next=h[v]; h[v]=tot;
}
void predfs(int u,int fa,int Dep){
dep[u]=Dep;
pre[u][]=fa;
for(int i=;i<Bas;i++) pre[u][i]=pre[pre[u][i-]][i-];
for(int i=h[u],v;i;i=g[i].next)
if((v=g[i].v)!=fa)
predfs(v,u,Dep+);
}
int getlca(int a,int b){
if(dep[a]<dep[b]) swap(a,b);
for(int i=Bas-;i>=;i--)
if(dep[pre[a][i]]>=dep[b]) a=pre[a][i];
if(a==b) return a;
for(int i=Bas-;i>=;i--)
if(pre[a][i]!=pre[b][i]) a=pre[a][i],b=pre[b][i];
return pre[a][];
}
int getdis(int x,int y){return (dep[x]-)+(dep[y]-)-*(dep[getlca(x,y)]-);}
void find(int u,int fa){
int maxs=;
size[u]=;
for(int i=h[u],v;i;i=g[i].next)
if(!cut[v=g[i].v]&&v!=fa){
find(v,u);
size[u]+=size[v];
if(size[v]>maxs) maxs=size[v];
}
if(sum-size[u]>maxs) maxs=sum-size[u];
if(maxs<nval) nrt=u,nval=maxs;
}
void dfs(int u,int fa,int dis,Heap &heap){
heap.push(dis);
for(int i=h[u],v;i;i=g[i].next)
if(!cut[v=g[i].v]&&v!=fa)
dfs(v,u,dis+,heap);
}
void solve(int u,int Fa){
cut[u]=; fa[u]=Fa;
for(int i=h[u],v;i;i=g[i].next)
if(!cut[v=g[i].v]){
nval=INF; nrt=; sum=size[u];
find(v,);
solve(nrt,u);
}
}
void change(int u,int v,int flag){
if(u==v){
if(flag){
b[u].push();
if(b[u].size()==) a.push(b[u].top());
}
else{
if(b[u].size()==) a.erase(b[u].top());
b[u].erase();
}
}
if(!fa[u]) return;
int f=fa[u],dis=getdis(f,v),last=c[u].top();
if(flag) c[u].push(dis); else c[u].erase(dis);
if((flag&&dis>last)||(!flag&&dis==last)){
a.erase(b[f].count());
b[f].erase(last);
if(flag) b[f].push(dis);
else b[f].push(c[u].top());
a.push(b[f].count());
}
change(f,v,flag);
}
int main(){
n=rd();
for(int i=,u,v;i<n;i++)
u=rd(),v=rd(),addEdge(u,v);
predfs(,,);
nval=INF; nrt=; sum=n;
find(,);
solve(nrt,);
for(int i=;i<=n;i++){
change(i,i,!st[i]);
st[i]^=;
cnt++;
}
char opt[];
int x;
q=rd();
while(q--){
scanf("%s",opt);
if(opt[]=='G'){
if(cnt==) puts("");
else if(cnt==) puts("-1");
else printf("%d\n",a.top());
}
else{
x=rd();
change(x,x,!st[x]);
st[x]^=;
if(st[x]) cnt++; else cnt--;
}
}
return ;
}

奇妙代码

【BZOJ1095】 Hide 捉迷藏的更多相关文章

  1. 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏

    简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ...

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

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

  3. [bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

    [bzoj1095][ZJOI2007]Hide 捉迷藏 2015年4月20日7,8876 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiaji ...

  4. 【BZOJ1095】捉迷藏(动态点分治)

    [BZOJ1095]捉迷藏(动态点分治) 题面 BZOJ 题解 动态点分治板子题 假设,不考虑动态点分治 我们来想怎么打暴力: \(O(n)DP\)求树的最长链 一定都会.不想解释了 所以,利用上面的 ...

  5. 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)

    1095: [ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉迷藏游戏 ...

  6. BZOJ_1095_[ZJOI2007]Hide 捉迷藏_动态点分治+堆

    BZOJ_1095_[ZJOI2007]Hide 捉迷藏_动态点分治+堆 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子 ...

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

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

  8. BZOJ1095: [ZJOI2007]Hide 捉迷藏【线段树维护括号序列】【思维好题】

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

  9. 「BZOJ1095」[ZJOI2007] Hide 捉迷藏

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

随机推荐

  1. 我的踩坑之旅-跨域问题引发bug

    场景: 由于业务原因需要在请求中添加一个信息表明请求的source,经过一轮方案的评审,大家共同决定把这source信息存放在消息header中.前端小伙伴听完之后心里暗自偷笑:就一行的代码的事,请求 ...

  2. 【转】Robust regression(稳健回归)

    Robust regression(稳健回归) 语法 b=robustfit(X,y) b=robustfit(X,y,wfun,tune) b=robustfit(X,y,wfun,tune,con ...

  3. Python实现XML文件解析

    1. XML简介 XML(eXtensible Markup Language)指可扩展标记语言,被设计用来传输和存储数据,已经日趋成为当前许多新生技术的核心,在不同的领域都有着不同的应用.它是web ...

  4. 利用多进程获取猫眼电影top100

    猫眼电影top100 是数据是在加载网页时直接就已经加载了的,所以可以通过requests.get()方法去获取这个url的数据,能过对得到的数据进行分析从而获得top100的数据, 把获取的数据存入 ...

  5. json模块和pickle模块的用法

    在python中,可以使用pickle和json两个模块对数据进行序列化操作 其中: json可以用于字符串或者字典等与python数据类型之间的序列化与反序列化操作 pickle可以用于python ...

  6. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [FFT 组合计数 容斥原理]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

  7. POJ Building roads [二分答案 2SAT]

    睡觉啦 #include <iostream> #include <cstdio> #include <cstring> #include <algorith ...

  8. react小结

    react基础小结 1. 例子 import React from 'react' import { render } from 'react-dom' // 定义组件 class Hello ext ...

  9. 针对Eclipse的maven Missing artifact com.microsoft.sqlserver:slqjdbc4:jar:4.0

    maven 中添加sqlserver 出错,报错内容 maven Missing artifact com.microsoft.sqlserver 解决方法这里先下载好jar包 ,然后maven命令执 ...

  10. Xcode intellisense meaning of letters in colored boxes like f,T,C,M,P,C,K,# etc

    in Xcode this is called "Code Sense". And these icons also exist in Xcode 3. Red: macros # ...