BZOJ 1095: [ZJOI2007]Hide 捉迷藏

Posted NeighThorn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1095: [ZJOI2007]Hide 捉迷藏相关的知识,希望对你有一定的参考价值。

1095: [ZJOI2007]Hide 捉迷藏

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 3585  Solved: 1480
[Submit][Status][Discuss]

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。

Source

分析:

简化一下就是询问树上最远的两个黑点的距离,会存在修改操作...

貌似有两种做法...

一种叫做动态点分治...貌似理解起来比较容易...然而代码...

一种叫做括号序列...跑得飞起...

动态点分治:

点分治的过程是选取重心来搞一搞...所以我们找到所有的重心,然后把这棵树建出来,树高是$log$的,然后我们在每个点上维护两个堆,第一个堆维护的是当前点的子树中所有黑点到当前点根节点的距离,第二个堆维护的是当前点所有子节点的堆顶,那么过当前点的最远点对就是第二堆的第一大和第二大的值之和...所以我们在全局维护一个堆,维护的是所有节点的最优值,也就是第二个堆的第一大和第二大值之和...

考虑修改操作,修改一个点只会影响一条链,所以就暴力修改就好...

括号序列:

下午补~~~

代码:

动态点分治:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
//by NeighThorn
using namespace std;

const int maxn=100000+5;

struct Heap{
	
	priority_queue<int> q1,q2;
	
	inline void Insert(int x){
		q1.push(x);
	}
	
	inline void Erase(int x){
		q2.push(x);
	}
	
	inline void Pop(void){
		while(q2.size()&&q1.top()==q2.top())
			q1.pop(),q2.pop();
		q1.pop();
	}
	
	inline int Top(void){
		while(q2.size()&&q1.top()==q2.top())
			q1.pop(),q2.pop();
		return q1.top();
	}
	
	inline int NextTop(void){
		int tmp=Top();Pop();
		int ans=Top();Insert(tmp);
		return ans;
	}
	
	inline int size(void){
		return q1.size()-q2.size();
	}
	
}pq[2][maxn],ans;

int n,q,cnt,tot,co[maxn],hd[maxn],to[maxn<<1],nxt[maxn<<1],ban[maxn<<1];
int f[maxn][25],fa[maxn],dep[maxn];

char opt[3];

inline void add(int x,int y){
	to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
}

inline int DfsSize(int x,int FA){
	int res=1;
	for(int i=hd[x];i!=-1;i=nxt[i])
		if(to[i]!=FA&&!ban[i])
			res+=DfsSize(to[i],x);
	return res;
}

inline void Insert(Heap &s){
	if(s.size()>=2)
		ans.Insert(s.Top()+s.NextTop());
}

inline void Erase(Heap &s){
	if(s.size()>=2)
		ans.Erase(s.Top()+s.NextTop());
}

inline int Find(int x,int FA,int siz,int &G){
	int S=1,flag=1;
	for(int i=hd[x];i!=-1;i=nxt[i])
		if(to[i]!=FA&&!ban[i]){
			int tmp=Find(to[i],x,siz,G);
			if(tmp>siz/2) flag=0;
			S+=tmp;
		}
	if(siz-S>siz/2) flag=0;
	if(flag) G=x;return S;
}

inline void dfs(int x,int FA,int d,Heap &s){
	s.Insert(d);
	for(int i=hd[x];i!=-1;i=nxt[i])
		if(to[i]!=FA&&!ban[i])
			dfs(to[i],x,d+1,s);
}

inline int divide(int x){
	int G,siz=DfsSize(x,-1);Find(x,-1,siz,G);
//	cout<<x<<" "<<G<<endl;
	pq[1][G].Insert(0);
	for(int i=hd[G];i!=-1;i=nxt[i])
		if(!ban[i]){
			ban[i]=ban[i^1]=1;
			Heap tmp;dfs(to[i],-1,1,tmp);
			int Tmp=divide(to[i]);
			fa[Tmp]=G;pq[0][Tmp]=tmp;
			pq[1][G].Insert(pq[0][Tmp].Top());
		}
	Insert(pq[1][G]);
	return G;
}

inline void dfs(int x,int FA){
	for(int i=hd[x];i!=-1;i=nxt[i])
		if(to[i]!=FA)
			f[to[i]][0]=x,dep[to[i]]=dep[x]+1,dfs(to[i],x);
}

inline void init(void){
	for(int j=1;j<=20;j++)
		for(int i=1;i<=n;i++)
			f[i][j]=f[f[i][j-1]][j-1];
}

inline int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	int d=dep[x]-dep[y];
	for(int i=20;i>=0;i--)
		if((d>>i)&1) x=f[x][i];
	if(x==y) return x;
	for(int i=20;i>=0;i--)
		if(f[x][i]!=f[y][i])
			x=f[x][i],y=f[y][i];
	return f[x][0];
}

inline int getdis(int x,int y){
	return dep[x]+dep[y]-2*dep[lca(x,y)];
}

inline void TurnOn(int x){
	Erase(pq[1][x]);
	pq[1][x].Erase(0);
	Insert(pq[1][x]);
	for(int i=x;fa[i];i=fa[i]){
		Erase(pq[1][fa[i]]);
		if(pq[0][i].size())
			pq[1][fa[i]].Erase(pq[0][i].Top());
		pq[0][i].Erase(getdis(x,fa[i]));
		if(pq[0][i].size())
			pq[1][fa[i]].Insert(pq[0][i].Top());
		Insert(pq[1][fa[i]]);
	}
}

inline void TurnOff(int x){
	Erase(pq[1][x]);
	pq[1][x].Insert(0);
	Insert(pq[1][x]);
	for(int i=x;fa[i];i=fa[i]){
		Erase(pq[1][fa[i]]);
		if(pq[0][i].size())
			pq[1][fa[i]].Erase(pq[0][i].Top());
		pq[0][i].Insert(getdis(x,fa[i]));
		if(pq[0][i].size())
			pq[1][fa[i]].Insert(pq[0][i].Top());
		Insert(pq[1][fa[i]]);
	}
}

signed main(void){
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
#endif
	scanf("%d",&n);memset(hd,-1,sizeof(hd));
	for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
	divide(1),dfs(1,-1),init();
	scanf("%d",&q);tot=n;
	for(int i=1;i<=n;i++) co[i]=1;
	for(int i=1,x;i<=q;i++){
		scanf("%s",opt);
		if(opt[0]==‘C‘){
			scanf("%d",&x);
			if(co[x]) TurnOn(x),tot--,co[x]=0;
			else TurnOff(x),tot++,co[x]=1;
		}
		else{
			if(tot<=1) printf("%d\n",tot-1);
			else printf("%d\n",ans.Top());
		}
	}
	return 0;
}

 


By NeighThorn

以上是关于BZOJ 1095: [ZJOI2007]Hide 捉迷藏的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1095: [ZJOI2007]Hide 捉迷藏

BZOJ1095[ZJOI2007]Hide 捉迷藏 动态树分治+堆

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

bzoj 1095[ZJOI2007]Hide 捉迷藏

Bzoj1095 [ZJOI2007]Hide 捉迷藏

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