【bzoj1095】[ZJOI2007]Hide 捉迷藏

2015年4月20日7,8876

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。

C.每个重心存所有子树到其距离
B.每个重心存各个子树最大值,即子结点堆C的最大值
A.全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和
 
 
 
C的意思是u这个节点,经过u,到达其父亲f的路径的所有距离,
B是维护所有的子节点的C的最大值,
A是维护各个B中的最大值。
 
动态点分治是树上动态添加节点,在这种情况下动态维护点分树的结构
 
这道题目的树的结构是不变的,所以建出点分树即可,
然后维护各个堆的值即可。
 
因为点分树上是log层的,堆维护也是log的,所有每次询问logn
修改logn logn,所有总复杂度是n log^2n
 
计算深度那里十分巧妙,用一个rmq记录,就是通过dfs访问顺序,然后进入一个点记录一次,
这样总共均摊是2*n,和边有关系,
然后rmq记录最小值,发现这个就是lca的深度
然后距离就比较好算了,O(1)算出,
 
 #include<cstring>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue> #define inf 1000000007
#define N 200007
#define ll long long
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if (ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int n,m,rt,dfn,sum,tot;
int bin[],Log[N];
int siz[N],f[N],dep[N];
int cnt,hed[N],rea[N],nxt[N];
int mn[][N],pos[N],fa[N];
bool vis[N],clo[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 ;
return A.top();
}
int size(){return A.size()-B.size();}
int stop()
{
if(size()<)return ;
int x=top();pop();
int y=top();push(x);
return y;
}
}A,B[],C[]; void add(int u,int v)
{
nxt[++cnt]=hed[u];
hed[u]=cnt;
rea[cnt]=v;
}
void dfs(int u,int fa)
{
mn[][++dfn]=dep[u],pos[u]=dfn;
for (int i=hed[u];i!=-;i=nxt[i])
{
int v=rea[i];
if (v==fa)continue;
dep[v]=dep[u]+;
dfs(v,u);
mn[][++dfn]=dep[u];
}
}
void get_root(int u,int fa)
{
siz[u]=,f[u]=;
for (int i=hed[u];i!=-;i=nxt[i])
{
int v=rea[i];
if (v==fa||vis[v])continue;
get_root(v,u);
siz[u]+=siz[v];
f[u]=max(f[u],siz[v]);
}
f[u]=max(f[u],sum-siz[u]);
if (f[u]<f[rt])rt=u;
}
void divide(int u,int par)
{
fa[u]=par,vis[u]=;int sums=sum;
for (int i=hed[u];i!=-;i=nxt[i])
{
int v=rea[i];
if (vis[v])continue;
if (siz[v]>siz[u]) sum=sums-siz[u];
else sum=siz[v];
rt=;
get_root(v,u);
divide(rt,u);
}
}
int rmq(int x,int y)
{
x=pos[x],y=pos[y];
if (y<x)swap(x,y);
int t=Log[y-x+];
return min(mn[t][x],mn[t][y-bin[t]+]);
}
int dis(int x,int y)
{
return dep[x]+dep[y]-*rmq(x,y);
}
void turn_off(int u,int v)
{
if (u==v)
{
B[u].push();
if (B[u].size()==)A.push(B[u].top());
}
if(!fa[u])return;
int f=fa[u],D=dis(f,v),tmp=C[u].top();
C[u].push(D);
if (D>tmp)
{
int mx=B[f].top()+B[f].stop(),size=B[f].size();
if (tmp)B[f].erase(tmp);
B[f].push(D);
int now=B[f].top()+B[f].stop();
if(now>mx)
{
if (size>=)A.erase(mx);
if (B[f].size()>=)A.push(now);
}
}
turn_off(f,v);
}
void turn_on(int u,int v)
{
if(u==v)
{
if(B[u].size()==)A.erase(B[u].top());
B[u].erase();
}
if(!fa[u])return;
int f=fa[u],D=dis(f,v),tmp=C[u].top();
C[u].erase(D);
if(D==tmp)
{
int mx=B[f].top()+B[f].stop(),size=B[f].size();
B[f].erase(D);
if(C[u].top())B[f].push(C[u].top());
int now=B[f].top()+B[f].stop();
if(now<mx)
{
if(size>=)A.erase(mx);
if(B[f].size()>=)A.push(now);
}
}
turn_on(f,v);
}
int main()
{
bin[]=;for (int i=;i<;i++)bin[i]=bin[i-]<<;//2的幂次
Log[]=-;for (int i=;i<=;i++)Log[i]=Log[i>>]+;
n=read();memset(hed,-,sizeof(hed));
for(int i=;i<n;i++)
{
int u=read(),v=read();
add(u,v),add(v,u);
} dfs(,);//预处理出深度 for (int i=;i<=Log[dfn];i++)
for (int j=;j<=dfn;j++)
if (j+bin[i]-<=dfn) mn[i][j]=min(mn[i-][j],mn[i-][j+bin[i-]]);
//预处理,处理出向下走2^x步的到达最浅的点,就是起lca的深度。 rt=,f[]=inf,sum=n;
get_root(,),divide(rt,);
for (int i=;i<=n;i++)
clo[i]=true;
for (int i=;i<=n;i++)turn_off(i,i);
tot=n;//tot记录当前多少灯是灭的。
// printf("%d\n",A.top()); char ch[];m=read();
while(m--)
{
scanf("%s",ch+);
if (ch[]=='G')
{
if (tot<=) printf("%d\n",tot-);
else printf("%d\n",A.top());
}
else
{
int x=read();
if (clo[x])turn_on(x,x),tot--;
else turn_off(x,x),tot++;
clo[x]^=;
}
}
}
 
 
 

[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治的更多相关文章

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

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

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

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

  3. BZOJ1095: [ZJOI2007]Hide 捉迷藏【动态点分治】

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

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

    题目链接 BZOJ1095 题解 传说中的动态点分治,一直不敢碰 今日一会,感觉其实并不艰涩难懂 考虑没有修改,如果不用树形dp的话,就得点分治 对于每个重心,我们会考虑其分治的子树内所有点到它的距离 ...

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

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

  6. 2019.01.10 bzoj1095: [ZJOI2007]Hide 捉迷藏(动态点分治)

    传送门 蒟蒻真正意义上做的第一道动态点分治! 题意:给一棵最开始所有点都是黑点的树,支持把点的颜色变成从黑/白色变成白/黑色,问当前状态树上两个最远黑点的距离. 思路: 首先考虑不带修改一次点分治怎么 ...

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

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

  8. bzoj千题计划245:bzoj1095: [ZJOI2007]Hide 捉迷藏

    http://www.lydsy.com/JudgeOnline/problem.php?id=1095 查询最远点对,带修改 显然可以用动态点分治 对于每个点,维护两个堆 堆q1[x] 维护 点分树 ...

  9. bzoj千题计划252:bzoj1095: [ZJOI2007]Hide 捉迷藏

    http://www.lydsy.com/JudgeOnline/problem.php?id=1095 点分树+堆 请去看 http://www.cnblogs.com/TheRoadToTheGo ...

随机推荐

  1. JS实现全排列

    https://www.jb51.net/article/39291.htm JavaScript全排列的六种算法 具体实现 算法一:交换(递归) 复制代码代码如下: <html xmlns=& ...

  2. Django models多表操作

    title: Django models多表操作 tags: Django --- 多表操作 单独创建第三张表的情况 推荐使用的是使用values/value_list,selet_related的方 ...

  3. C++ Stack 与String

    // ConsoleApplication1.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. // #include "pch.h" ...

  4. 解决在matplotlib使用中文的问题

    原生的matplotlib并不支持直接使用中文,而需要修改一下相应的文件,上网搜了下,找到一个最简洁的办法. NO.1 找到matplotlibrc文件 C:\Python26\Lib\site-pa ...

  5. Python基础——模块与包

    在Python中,可以用import导入需要的模块.包.库.文件等. 把工作路径导入系统路径 import os#os是工作台 import sys#sys是系统 sys.path.append(os ...

  6. Python模块(二)(序列化)

    1. namedtuple 命名元组->类似创建了一个类 from collections import namedtuple p = namedtuple("Point", ...

  7. 打印机增强软件pdfpro

     http://3dx.pc6.com/gm1/pdfpro.zip    

  8. XenServer 6.5 安装

    为了方便截图我下面的所有操作都是在VMware Workstation 11 上面完成的,但在之后的所有Citrix产品的操作中都将会在物理环境完成,物理机安装XS的步骤和下面是相同的. 1.打开Wo ...

  9. Windows中redis的下载及安装、设置

    本文是转载自:https://www.cnblogs.com/wxjnew/p/9160855.html 除了原文的东西还有自己遇到的一些问题,这里记录一下. 一.下载: 下载地址: https:// ...

  10. python中子进程不支持input()函数输入

    错误的源代码: import socketimport threadingimport multiprocessing# 创建socketserve_socket = socket.socket(so ...