[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治
【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
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
3
3
4
HINT
对于100%的数据, N ≤100000, M ≤500000。
#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 捉迷藏 点分树,动态点分治的更多相关文章
- BZOJ1095: [ZJOI2007]Hide 捉迷藏【线段树维护括号序列】【思维好题】
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- 动态点分治:Bzoj1095: [ZJOI2007]Hide 捉迷藏
简介 这是我自己的一点理解,可能写的不好 点分治都学过吧.. 点分治每次找重心把树重新按重心的深度重建成了一棵新的树,称为分治树 这个树最多有log层... 动态点分治:记录下每个重心的上一层重心,这 ...
- BZOJ1095: [ZJOI2007]Hide 捉迷藏【动态点分治】
Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩 捉迷藏游戏.他们的家很大且构造很奇特,由N个屋子和N-1条 ...
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 【动态点分治 + 堆】
题目链接 BZOJ1095 题解 传说中的动态点分治,一直不敢碰 今日一会,感觉其实并不艰涩难懂 考虑没有修改,如果不用树形dp的话,就得点分治 对于每个重心,我们会考虑其分治的子树内所有点到它的距离 ...
- BZOJ1095 [ZJOI2007]Hide 捉迷藏 动态点分治 堆
原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ1095.html 题目传送门 - BZOJ1095 题意 有 N 个点,每一个点是黑色或者白色,一开始所 ...
- 2019.01.10 bzoj1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
传送门 蒟蒻真正意义上做的第一道动态点分治! 题意:给一棵最开始所有点都是黑点的树,支持把点的颜色变成从黑/白色变成白/黑色,问当前状态树上两个最远黑点的距离. 思路: 首先考虑不带修改一次点分治怎么 ...
- bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
好迷啊...感觉动态点分治就是个玄学,蜜汁把树的深度缩到logn (静态)点分治大概是递归的时候分类讨论: 1.答案经过当前点,暴力(雾)算 2.答案不经过当前点,继续递归 由于原树可以长的奇形怪状( ...
- bzoj千题计划245:bzoj1095: [ZJOI2007]Hide 捉迷藏
http://www.lydsy.com/JudgeOnline/problem.php?id=1095 查询最远点对,带修改 显然可以用动态点分治 对于每个点,维护两个堆 堆q1[x] 维护 点分树 ...
- bzoj千题计划252:bzoj1095: [ZJOI2007]Hide 捉迷藏
http://www.lydsy.com/JudgeOnline/problem.php?id=1095 点分树+堆 请去看 http://www.cnblogs.com/TheRoadToTheGo ...
随机推荐
- EditPlus 3.7激活码注册码
EditPlus3.7激活教程以及EditPlus3.7激活码使用方法 EditPlus是一款功能齐全的文字编辑器,搭配其他的插件还可以实现很多的功能,还可以编辑和编译Java,调试程序等,主要用来打 ...
- SpringMVC-概述和入门程序
三层架构和MVC B/S三层架构 表现层:web层,一般使用MVC模型 业务层:service层 持久层:dao层 MVC模型 Model:数据模型,JavaBean的类,用来进行数据封装 View: ...
- JS实现全排列
https://www.jb51.net/article/39291.htm JavaScript全排列的六种算法 具体实现 算法一:交换(递归) 复制代码代码如下: <html xmlns=& ...
- vue axios 请求 https 的特殊处理
最近遇到自签发的CA证书,在前端axios请求https请求时,无法自动加载证书. 解决方法:将无法加载的请求在浏览器新窗口手动加载,选择继续连接. 重新加载,问题解决. 根本原因:因为自签发证书,浏 ...
- NOIP模拟赛 无线通讯网
[题目描述] 国防部计划用无线网络连接若干个边防哨所.2种不同的通讯技术用来搭建无线网络:每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫星电话线路的哨所(两边都 ...
- 18.Yii2.0框架模型修改记录 和 修改点击量
目录 修改数据 修改点击量 修改数据 上面要 use app\models\Article; //修改 //http://yii.com/?r=home/Edit public function ac ...
- Python基础——集合(set)
集合可以去除掉列表中重复的元素. 创建 list1=[123,123,456,789] list1=set(list1) list1 set1=set() type(set1) set1=set([1 ...
- CF 510b Fox And Two Dots
Fox Ciel is playing a mobile puzzle game called "Two Dots". The basic levels are played on ...
- HDU 5025 Saving Tang Monk(状态转移, 广搜)
#include<bits/stdc++.h> using namespace std; ; ; char G[maxN][maxN], snake[maxN][maxN]; ]; int ...
- Python之code对象与pyc文件(三)
上一节:Python之code对象与pyc文件(二) 向pyc写入字符串 在了解Python如何将字符串写入到pyc文件的机制之前,我们先来了解一下结构体WFILE: marshal.c typede ...