zoukankan      html  css  js  c++  java
  • 【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

    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。

    题解:将点分治时经过的所有节点取出来,按分治的先后顺序构成一棵树,叫做点分树,它的树高是logn的,我们就可以利用这个性质来搞一些事情,这就叫做动态点分治。(个人理解,勿喷)

    然后呢,本题要求的是虚树的直径,那么我们沿用树形DP的思想,维护每个子树中深度的最大和次大值,我们开一个堆A即可。但是要求最大和次大值不能再同一个儿子的子树中,那么我们就需要对于每个儿子都维护一个堆B,用堆B来更新父亲的堆A。最后为了统计答案,我们再开一个全局的堆C即可。

    所以本题一共用了3个堆。

    B:维护每个点的子树中(所说的子树全是指分治结构的子树)所有点到该点的父亲的距离。
    A:维护每个点的所有儿子(分治结构的儿子)的B的堆顶。
    C:维护所有堆A的最大值+次大值。

    可删除的堆怎么写?开两个堆,一个代表所有元素,一个代表已经被删除的元素就行了。

    鉴于BZ老爷机的速度,我们求两点间还是用RMQ-LCA吧~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int maxn=100010;
    int n,m,mn,rt,tot,cnt,sum;
    int to[maxn<<1],next[maxn<<1],head[maxn],fa[maxn],dep[maxn],pos[maxn];
    int md[18][maxn<<1],Log[maxn<<1],siz[maxn],q[maxn];
    bool light[maxn],vis[maxn];
    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();
    		return !A.size()?0:A.top();
    	}
    	int top2()
    	{
    		if(size()<2)	return 0;
    		int x=top();	pop();
    		int y=top();	push(x);
    		return y;
    	}
    	int size()	{return A.size()-B.size();}
    }p1[maxn],p2[maxn],p;
    char str[10];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int lca(int a,int b)
    {
    	a=pos[a],b=pos[b];
    	if(a>b)	swap(a,b);
    	int k=Log[b-a+1];
    	return min(md[k][a],md[k][b-(1<<k)+1]);
    }
    int dis(int a,int b)
    {
    	return dep[a]+dep[b]-2*lca(a,b);
    }
    void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void getr(int x,int fa)
    {
    	siz[x]=1;
    	int tmp=0,i;
    	for(i=head[x];i!=-1;i=next[i])	if(to[i]!=fa&&!vis[to[i]])
    		getr(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]);
    	tmp=max(tmp,tot-siz[x]);
    	if(tmp<mn)	mn=tmp,rt=x;
    }
    void solve(int x)
    {
    	vis[x]=1,q[++q[0]]=x;
    	for(int i=head[x];i!=-1;i=next[i])	if(!vis[to[i]])	tot=siz[to[i]],mn=1<<30,getr(to[i],x),fa[rt]=x,solve(rt);
    }
    void dfs(int x)
    {
    	md[0][++pos[0]]=dep[x],pos[x]=pos[0];
    	for(int i=head[x];i!=-1;i=next[i])	if(!dep[to[i]])	dep[to[i]]=dep[x]+1,dfs(to[i]),md[0][++pos[0]]=dep[x];
    }
    void turnoff(int x,int y)
    {
    	if(x==y)
    	{
    		p2[x].push(0);
    		if(p2[x].size()==2)	p.push(p2[x].top());
    	}
    	if(!fa[x])	return ;
    	int f=fa[x],d=dis(f,y),tp=p1[x].top();
    	p1[x].push(d);
    	if(d>tp)
    	{
    		int mx=p2[f].top()+p2[f].top2(),sz=p2[f].size();
    		if(tp)	p2[f].erase(tp);
    		p2[f].push(d);
    		int nx=p2[f].top()+p2[f].top2();
    		if(nx>mx)
    		{
    			if(sz>=2)	p.erase(mx);
    			if(p2[f].size()>=2)	p.push(nx);
    		}
    	}
    	turnoff(f,y);
    }
    void turnon(int x,int y)
    {
    	if(x==y)
    	{
    		if(p2[x].size()==2)	p.erase(p2[x].top());
    		p2[x].erase(0);
    	}
    	if(!fa[x])	return ;
    	int f=fa[x],d=dis(f,y);
    	p1[x].erase(d);
    	int tp=p1[x].top();
    	if(d>tp)
    	{
    		int mx=p2[f].top()+p2[f].top2(),sz=p2[f].size();
    		p2[f].erase(d);
    		if(tp)	p2[f].push(tp);
    		int nx=p2[f].top()+p2[f].top2();
    		if(nx<mx)
    		{
    			if(sz>=2)	p.erase(mx);
    			if(p2[f].size()>=2)	p.push(nx);
    		}
    	}
    	turnon(f,y);
    }
    int main()
    {
    	n=rd();
    	int i,j,a,b;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	dep[1]=1,dfs(1);
    	for(i=2;i<=2*n-1;i++)	Log[i]=Log[i>>1]+1;
    	for(j=1;(1<<j)<=2*n-1;j++)
    		for(i=1;i+(1<<j)-1<=2*n-1;i++)
    			md[j][i]=min(md[j-1][i],md[j-1][i+(1<<(j-1))]);
    	tot=n,mn=1<<30,getr(1,0),solve(rt);
    	for(i=1;i<=n;i++)	turnoff(i,i);
    	m=rd(),sum=n;
    	for(i=1;i<=m;i++)
    	{
    		scanf("%s",str);
    		if(str[0]=='G')
    		{
    			if(sum>=2)	printf("%d
    ",p.top());
    			else	if(sum==1)	printf("0
    ");
    			else	printf("-1
    ");
    		}
    		else
    		{
    			a=rd();
    			if(light[a])	sum++,light[a]=0,turnoff(a,a);
    			else	sum--,light[a]=1,turnon(a,a);
    		}
    	}
    	return 0;
    }//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
  • 相关阅读:
    postgresql 添加触发器
    postgresql 操作
    postgresql 更新自增变量
    java8 stream api 文件流甚是牛逼
    fastjson妙用
    idea中springboot内置tomcat控制台中文乱码解决
    linux中开放某个端口
    idea中application.properties文件防止中文汉字自动转换成unicode编码解决办法
    使用vue开源项目vue-framework-wz遇到的问题以及解决方案
    rsync的使用
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7451808.html
Copyright © 2011-2022 走看看