【刷题】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。
Solution
线段树维护直径
第一反应就是线段树,感觉动态点分和括号序列太繁琐了
树剖后用线段树搞就好了,修改也很方便
线段树维护直径基于这样一条性质:两棵树合并,新的直径的两个端点一定是原两棵树直径四个端点之二
具体可以看这里
#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10;
int n,m,e,beg[MAXN],nex[MAXN<<1],to[MAXN<<1],Mn[22][MAXN<<2],dep[MAXN],st[MAXN],ed[MAXN],cnt,hson[MAXN],size[MAXN],bcnt,black[5],lst[MAXN],ap[MAXN],lg[MAXN<<2],tot,fa[MAXN];
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
	to[++e]=y;
	nex[e]=beg[x];
	beg[x]=e;
}
inline void dfs1(int x,int f)
{
	int res=0;
	Mn[0][ap[x]=++tot]=x;
	dep[x]=dep[f]+1;size[x]=1;fa[x]=f;
	for(register int i=beg[x];i;i=nex[i])
	{
		if(to[i]!=f)
		{
			dfs1(to[i],x);
			size[x]+=size[to[i]];
			if(size[to[i]]>res)res=size[to[i]],hson[x]=to[i];
		}
		Mn[0][++tot]=x;
	}
}
inline void dfs2(int x,int tp)
{
	st[x]=++cnt;lst[cnt]=x;
	if(hson[x])dfs2(hson[x],tp);
	for(register int i=beg[x];i;i=nex[i])
		if(to[i]==fa[x]||to[i]==hson[x])continue;
		else dfs2(to[i],to[i]);
	ed[x]=cnt;
}
inline int LCA(int u,int v)
{
	int l=ap[u],r=ap[v];
	if(l>r)std::swap(l,r);
	int k=lg[r-l+1];
	return dep[Mn[k][l]]<dep[Mn[k][r-(1<<k)+1]]?Mn[k][l]:Mn[k][r-(1<<k)+1];
}
inline int dist(int u,int v)
{
	return dep[u]+dep[v]-(dep[LCA(u,v)]<<1);
}
inline std::pair<int,int> find()
{
	int res=-1;
	std::pair<int,int> ps;
	std::sort(black,black+bcnt+1);
	bcnt=std::unique(black,black+bcnt+1)-black-1;
	for(register int i=1;i<=bcnt;++i)
		for(register int j=i,now;j<=bcnt;++j)
		{
			now=dist(black[i],black[j]);
			if(now>res)res=now,ps=std::make_pair(black[i],black[j]);
		}
	return ps;
}
#define Mid ((l+r)>>1)
#define ls rt<<1
#define rs rt<<1|1
#define lson ls,l,Mid
#define rson rs,Mid+1,r
#define ft first
#define sd second
struct Segment_Tree{
	std::pair<int,int> pnt[MAXN<<2];
	int col[MAXN<<2];
	inline std::pair<int,int> Merge(std::pair<int,int> lp,std::pair<int,int> rp)
	{
		bcnt=0;
		if(lp.ft&&col[lp.ft])black[++bcnt]=lp.ft;
		if(lp.sd&&col[lp.sd])black[++bcnt]=lp.sd;
		if(rp.ft&&col[rp.ft])black[++bcnt]=rp.ft;
		if(rp.sd&&col[rp.sd])black[++bcnt]=rp.sd;
		if(!bcnt)return std::make_pair(0,0);
		else return find();
	}
	inline void Build(int rt,int l,int r)
	{
		if(l==r)pnt[rt]=std::make_pair(lst[l],lst[r]),col[lst[l]]=1;
		else Build(lson),Build(rson),pnt[rt]=Merge(pnt[ls],pnt[rs]);
	}
	inline void Update(int rt,int l,int r,int ps)
	{
		if(l==r&&r==ps)
		{
			col[lst[l]]^=1;
			if(col[lst[l]])pnt[rt]=std::make_pair(lst[l],lst[r]);
			else pnt[rt]=std::make_pair(0,0);
		}
		else
		{
			if(ps<=Mid)Update(lson,ps);
			else Update(rson,ps);
			pnt[rt]=Merge(pnt[ls],pnt[rs]);
		}
	}
	inline std::pair<int,int> Query(int rt,int l,int r,int L,int R)
	{
		if(L==l&&r==R)return pnt[rt];
		else
		{
			if(R<=Mid)return Query(lson,L,R);
			else if(L>Mid)Query(rson,L,R);
			else return Merge(Query(lson,L,Mid),Query(rson,Mid+1,R));
		}
	}
};
Segment_Tree T;
#undef Mid
#undef ls
#undef rs
#undef lson
#undef rson
#undef ft
#undef sd
inline void init()
{
	dfs1(1,0);dfs2(1,1);
	for(register int i=2;i<=tot;++i)lg[i]=lg[i>>1]+1;
	for(register int j=1;j<=lg[tot];++j)
		for(register int i=1;i+(1<<j)<=tot;++i)Mn[j][i]=dep[Mn[j-1][i]]<dep[Mn[j-1][i+(1<<j-1)]]?Mn[j-1][i]:Mn[j-1][i+(1<<j-1)];
	T.Build(1,1,n);
}
int main()
{
	read(n);
	for(register int i=1;i<n;++i)
	{
		int u,v;read(u);read(v);
		insert(u,v);insert(v,u);
	}
	init();
	read(m);
	while(m--)
	{
		char opt[1];scanf("%s",opt);
		if(opt[0]=='G')
		{
			std::pair<int,int> ans=T.Query(1,1,n,st[1],ed[1]);
			if(!ans.first)puts("-1");
			else write(dist(ans.first,ans.second),'\n');
		}
		if(opt[0]=='C')
		{
			int x;read(x);
			T.Update(1,1,n,st[x]);
		}
	}
	return 0;
}
【刷题】BZOJ 1095 [ZJOI2007]Hide 捉迷藏的更多相关文章
- 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 捉迷藏 ——动态点分治
		[题目分析] 这题好基啊. 先把分治树搞出来.然后每个节点两个堆. 第一个堆保存这个块里的所有点(即分治树中的所有儿子)到分治树上的父亲的距离. 第二个堆保存分治树子树中所有儿子第一个堆的最大值. 建 ... 
- 洛谷 P2056 [ZJOI2007]捉迷藏 || bzoj 1095: [ZJOI2007]Hide 捉迷藏 || 洛谷 P4115 Qtree4 || SP2666 QTREE4 - Query on a tree IV
		意识到一点:在进行点分治时,每一个点都会作为某一级重心出现,且任意一点只作为重心恰好一次.因此原树上任意一个节点都会出现在点分树上,且是恰好一次 https://www.cnblogs.com/zzq ... 
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏 动态点分治+堆
		写了7k多,可以说是一己之力切掉了这道毒瘤题~ 开 $3$ 种堆,分别维护每个子树最大深度,以及每个节点在点分树中对父亲的贡献,和全局的最优解. 由于需要支持堆的删除,所以写起来特别恶心+麻烦. 细节 ... 
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
		这个嘛= =链剖貌似可行,不过好像代码长度很长,懒得打(其实是自己太弱了QAQ)百度了一下才知道有一种高大上的叫括号序列的东西= = 岛娘真是太厉害了,先丢链接:http://www.shuizilo ... 
- [BZOJ 1095] [ZJOI2007]Hide 捉迷藏——线段树+括号序列(强..)
		神做法-%dalao,写的超详细 konjac的博客. 如果觉得上面链接的代码不够优秀好看,欢迎回来看本蒟蒻代码- CODE WITH ANNOTATION 代码中−6-6−6表示左括号'[',用−9 ... 
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(动态点分治)
		传送门 解题思路 点分树其实就是在点分治的基础上,把重心连起来.这样树高是\(log\)的,可以套用数据结构进行操作.这道题是求最远距离,所以每个点维护两个堆,分别表示所管辖的子树的最远距离和到父节点 ... 
随机推荐
- perf + 火焰图用法 小结
			要对新服务做性能测试,分析代码热点,初识perf,做下总结 perf + 火焰图用法 perf简介 Perf (Performance Event), Linux 系统原生提供的性能分析工具, 会返回 ... 
- Android手机测试-ddms&monitor-抓crash,log
			1.安装adb offline解决办法: 原因就是android 4.2以上的版本过高,sdk的adb驱动不匹配,需要升级.我原本的adb是1.0.29,升级为1.0.31,问题就解决了. 2.安装s ... 
- Codeforces Round #502 (in memory of Leopoldo Taravilse, Div. 1 + Div. 2) E. The Supersonic Rocket
			这道题比赛之后被重新加了几个case,很多人现在都过不了了 算法就是先求凸包,然后判断两个凸包相等 我们可以吧凸包序列化为两点距离和角度 角度如果直接拿向量的叉积是不对的,,因为钝角和锐角的叉积有可能 ... 
- Linux 优化详解
			一.引子 系统优化是一项复杂.繁琐.长期的工作,优化前需要监测.采集.测试.评估,优化后也需要测试.采集.评估.监测,而且是一个长期和持续的过程,不是说现在又花了.测试了,以后就可以一劳永逸,而不是说 ... 
- 百度地图之自动提示--autoComplete
			<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ... 
- Teaching Machines to Understand Us 让机器理解我们 之一 引言
			Teaching Machines to Understand Us By Tom Simonite MIT Technology Review Vol.118 No.5 2015 让机器理解我 ... 
- shell基础 -- 基本语法
			本文介绍一下 shell 的语法. 一.变量 在 shell 里,使用变量之前通常并不需要事先为他们做出声明,需要使用的时候直接创建就行了.默认情况下,所有变量都被看做字符串并以字符串来存储,即使它们 ... 
- JAVA学习笔记--组合与继承
			JAVA一个很重要的功能就是代码的可复用性,代码复用可以大大提升编程效率.这里主要介绍两种代码复用方式:组合和继承. 一.组合 组合比较直观,只需在新的类中产生现有类的对象,新的类由现有类的对象组成, ... 
- Mysql  表创建语句
			# 新建bigData数据库 CREATE DATABASE bigData; USE bigData; # 创建dept表 CREATE TABLE dept( id INT UNSIGNED PR ... 
- Python:字符串中引用外部变量的3种方法
			方法一: username=input('username:') age=input('age:') job=input('job:') salary=input('salary') info1='' ... 
