BZOJ_1095_[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。


终于看明白点分树是啥了。。。

点分树上每个节点相当于维护他管辖的那些点。然后根据树高log可以支持一些操作。

不过由于点分树上的边不一定在原树上存在,通常我们需要求两点间距离,这时用O(nlogn)-O(1)的ST表就比较快。

说回这道题,开3个堆。h1[x]表示点分树上x的父亲到所管辖的所有点的距离。

这步空间为nlogn,因为每个点最多出现log次。

h2[x]存点分树上所有儿子的h1[son]堆顶。

h3存全局所有h2的最大值和最小值。

每次修改需要堆修改,再开一个堆即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define N 100050
#define GG puts("FUCK")
int n,head[N],to[N<<1],nxt[N<<1],cnt,totot;
int root,f[20][N<<1],g[N],used[N],sum,siz[N],tot,sta[N],pos[N],Lg[N<<1],dep[N],fa[N];
inline char nc() {
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
int rd() {
int x=0; char s=nc();
while(s<'0'||s>'9') s=nc();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
return x;
}
char rc() {
char s=nc();
while(s!='G'&&s!='C') s=nc();
return s;
}
struct Heap {
std::priority_queue<int>q,p;
void update() {
while((!q.empty())&&(!p.empty())&&q.top()==p.top()) q.pop(),p.pop();
}
void push(int x) {q.push(x);update();}
void pop() {q.pop();update();}
void del(int x) {p.push(x);update();}
int top() {update(); return q.top();}
int siz() {return q.size()-p.size();}
int num() {
int a=top(); pop();
int b=top(); push(a);
return a+b;
}
}h1[N],h2[N],h3;
void lca_init() {
int i,j;
Lg[0]=-1;
for(i=1;i<=tot;i++) Lg[i]=Lg[i>>1]+1;
for(i=1;(1<<i)<=tot;i++) {
for(j=1;j+(1<<i)-1<=tot;j++) {
f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]);
}
}
}
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void dfs(int x,int y) {
int i;
f[0][++tot]=dep[x]; pos[x]=tot;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y) {
dep[to[i]]=dep[x]+1;
dfs(to[i],x);
f[0][++tot]=dep[x];
}
}
}
int dis(int x,int y) {
int dx=dep[x],dy=dep[y];
x=pos[x],y=pos[y]; if(x>y) swap(x,y);
int len=Lg[y-x+1];
int lcadep=min(f[len][x],f[len][y-(1<<len)+1]);
return dx+dy-2*lcadep;
}
void get_root(int x,int y) {
int i; siz[x]=1; g[x]=0;
for(i=head[x];i;i=nxt[i]) {
if(!used[to[i]]&&to[i]!=y) {
get_root(to[i],x);
siz[x]+=siz[to[i]];
g[x]=max(g[x],siz[to[i]]);
}
}
g[x]=max(g[x],sum-siz[x]);
if(g[x]<g[root]) root=x;
}
void solve(int x) {
int i; used[x]=1;
for(i=head[x];i;i=nxt[i]) {
if(!used[to[i]]) {
sum=siz[to[i]]; root=0;
get_root(to[i],0);
fa[root]=x;
solve(root);
}
}
}
void erase(int p) {if(h2[p].siz()>=2) h3.del(h2[p].num());}
void insert(int p) {if(h2[p].siz()>=2) h3.push(h2[p].num());}
void guanshang(int x) {
erase(x); h2[x].push(0); insert(x);
int t;
for(t=x;fa[t];t=fa[t]) {
erase(fa[t]);
if(h1[t].siz()) h2[fa[t]].del(h1[t].top());
h1[t].push(dis(fa[t],x)); h2[fa[t]].push(h1[t].top());
insert(fa[t]);
}
}
void dakai(int x) {
erase(x); h2[x].del(0); insert(x);
int t;
for(t=x;fa[t];t=fa[t]) {
erase(fa[t]);
h2[fa[t]].del(h1[t].top()); h1[t].del(dis(fa[t],x));
// printf("%d\n",dis(fa[t],x));
if(h1[t].siz()) h2[fa[t]].push(h1[t].top());
insert(fa[t]);
}
}
int main() {
n=rd();
int i,x,y;
for(i=1;i<n;i++) {
x=rd(); y=rd(); add(x,y); add(y,x);
}
dfs(1,0); lca_init();
g[0]=1<<30; sum=n; get_root(1,0); solve(root);
// for(i=1;i<=n;i++) printf("%d\n",fa[i]);
for(i=1;i<=n;i++) guanshang(i),sta[i]=1;
int m=rd(); totot=n;
while(m--) {
char s=rc();
if(s=='G') {
if(totot<=1) printf("%d\n",totot-1);
else printf("%d\n",h3.top());
}else {
x=rd();
// printf("%d\n",x);
if(sta[x]) {
totot--; sta[x]=0;
dakai(x);
}else {
totot++; sta[x]=1;
guanshang(x);
}
}
}
}

BZOJ_1095_[ZJOI2007]Hide 捉迷藏_动态点分治+堆的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 终极报错解决方案:Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger failed with

    遇到这个报错的时候,不要慌 Error:Execution failed for task ':app:processDebugManifest'. > Manifest merger fail ...

  2. 在win7上安装visual c++ 2008 redistributable 发生错误error 1935

     方案一.原来服务"Windows Modules Installer"被禁用了, 启用该服务后, 问题就解决了.  方案二. 1.点开始——在运行框里输入regedit,按回车键 ...

  3. win10任务管理器开机老是自己打开

    win10任务管理器开机老是自己打开 学习了:https://zhidao.baidu.com/question/332868722086816045.html 还没有注意过这个东西:系统失败-> ...

  4. HttpClient获取Cookie的两种方式

    转载:http://blog.csdn.net/zhangbinu/article/details/72777620 一.旧版本的HttpClient获取Cookies p.s. 该方式官方已不推荐使 ...

  5. iframe截取站点的部分内容

    <div style="width:630px;height:350px;overflow:hidden;border:0px">                  & ...

  6. USB通讯协议

    首先要了解USB枚举过程(自己百度) https://blog.csdn.net/MyArrow/article/details/8270029 USB通讯协议 0. 基本概念 一个[传输](控制.批 ...

  7. linux查看进程、端口

    1 查看进程pidps -ef|grep tomcat 2 查看进程占用的端口netstat -ntlp|grep pid 3 查看端口对应的进程号lsof -i:portid

  8. 服务管理-DHCP、NTP、SSH

    DHCP协议的作用及原理 1.寻找server 当DHCP客户端第一次登陆网络的时候,也就是客户发现本机上没有任何ip资料设定,他会向网路发送一个dhcpdiscover封包.因为客户端还不知道自己属 ...

  9. 关于erlang反编译的东西

    在查阅了相关文档,想了解erlang反编译的东西.当然,源码可以打包成可以获取源码的,也可以保护源码的. 在ebin下,如果没有或者找不到源码,可以进行反编译,由beam文件得到erl文件. 可以通过 ...

  10. 五、WEB框架基础(1)

    框架与架构 Python语言有很多web框架,主要是四个,企业级框架Django,高并发处理框架Tornado,快速开发框架Flask,自定义协议框架Twisted. 全栈网络框架封装了网络通信/线程 ...