zoukankan      html  css  js  c++  java
  • 【ZJOI2007】捉迷藏

    题面

    Description

    Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。

    某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。

    他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,

    这N-1条走廊的分布使得任意两个屋子都互相可达。

    游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。

    在起初的时候,所有的灯都没有被打开。

    每一次,孩子们只会躲藏在没有开灯的房间中,

    但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。

    为了评估某一次游戏的复杂性,

    Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。

    我们将以如下形式定义每一种操作:

      img

    Input

    输入文件hide.in第一行包含一个整数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

    对于20%的数据,N≤50, Q≤100;

    对于60%的数据,N≤3000, Q≤10000;

    对于100%的数据,N≤100000, Q≤500000。

    题目分析

    动态询问多组点对信息,所以使用动态点分治。

    根据点分治的基本思路,

    对于一个重心,我们通常记录经过重心的路径来统计答案。

    这里我们沿用这种思路,设亮着的房间为白点,黑着的房间为黑点。

    对于某个重心(w),记录每个子树(v)中的黑点到(w)的最长链(每个子树只能贡献一个,避免重复)。

    计算该重心对答案的贡献时直接取堆(c[w])中的最大值+次大值即可。


    由于有删除操作,我们要能够迅速更新最长链的方法。

    于是,我们对每个节点(v),再开一个堆(up),记录以(v)为根的子树到(v)(parent)的最长链。

    注意:

    上面的(parent)指的是点分树上的父亲。

    然后再维护一个(ans)堆记录答案。


    还有一个注意事项,由于要支持堆中的删除操作,需要额外建一个堆维护删除信息。

    代码实现

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<iomanip>
    #include<cstdlib>
    #include<queue>
    #define MAXN 0x7fffffff
    typedef long long LL;
    const int N=100005;
    using namespace std;
    inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
    int h[N],cnt;
    struct Edge{int to,next;}g[N<<1];
    void AddEdge(int x,int y){g[++cnt].to=y,g[cnt].next=h[x],h[x]=cnt;}
    
    int fa[N],dep[N];
    int size[N],son[N],tp[N];
    void Dfs1(int x){
    	size[x]=1;
    	for(int i=h[x];i;i=g[i].next){
    		int to=g[i].to;
    		if(to==fa[x])continue;
    		fa[to]=x,dep[to]=dep[x]+1;
    		Dfs1(to),size[x]+=size[to];
    		if(size[to]>size[son[x]])son[x]=to;
    	}
    }
    void Dfs2(int x,int top){
    	tp[x]=top;
    	if(son[x])Dfs2(son[x],top);
    	for(int i=h[x];i;i=g[i].next){
    		int to=g[i].to;
    		if(to==fa[x]||to==son[x])continue;
    		Dfs2(to,to);
    	}
    }
    int LCA(int x,int y){
    	while(tp[x]^tp[y]){
    		if(dep[tp[x]]<dep[tp[y]])y=fa[tp[y]];
    		else x=fa[tp[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    int dis(int x,int y){return dep[x]+dep[y]-2*dep[LCA(x,y)];}
    
    struct Heap{
    	priority_queue<int>q,del;
    	void push(int x){q.push(x);}
    	void erase(int x){del.push(x);}
    	int top(){
    		while(del.size()&&q.top()==del.top())q.pop(),del.pop();
    		return q.top();
    	}
    	void Pop(){
    		while(del.size()&&q.top()==del.top())q.pop(),del.pop();
    		q.pop();
    	}
    	int sec(){
    		int tmp=top();Pop();
    		int x=top();push(tmp);
    		return x;
    	}
    	int size(){return q.size()-del.size();}
    }c[N],up[N],ans;
    
    int n,num,sum,prt[N];
    int rt,sz[N],mx[N];
    bool vis[N],light[N];
    void to_ans(int v,bool f){
    	if(c[v].size()>1){
    		int x=c[v].top()+c[v].sec();
    		f?ans.push(x):ans.erase(x);
    	}
    }
    void Explore(int x,int fa,int top){
    	up[top].push(dis(x,prt[top]));
    	for(int i=h[x];i;i=g[i].next){
    		int to=g[i].to;
    		if(vis[to]||to==fa)continue;
    		Explore(to,x,top);
    	}
    }
    void Get_size(int x,int fa) {
    	sz[x]=1;
    	for(int i=h[x];i;i=g[i].next) {
    		int to=g[i].to;
    		if(to==fa||vis[to]) continue;
    		Get_size(to,x);
    		sz[x]+=sz[to];
    	}
    }
    void Get_root(int x,int fa){
    	mx[x]=0;
    	for(int i=h[x];i;i=g[i].next){
    		int to=g[i].to;
    		if(to==fa||vis[to])continue;
    		Get_root(to,x);
    		mx[x]=max(mx[x],sz[to]);
    	}
    	mx[x]=max(mx[x],sum-sz[x]);
    	if(mx[rt]>mx[x])rt=x;
    }
    void Solve(int x){
    	vis[x]=1,c[x].push(0);
    	for(int i=h[x];i;i=g[i].next){
    		int to=g[i].to;
    		if(vis[to]||to==prt[x])continue;
    		Get_size(to,0),sum=sz[to];
    		rt=0,Get_root(to,0);
    		prt[rt]=x;
    		Explore(rt,0,rt);
    		c[x].push(up[rt].top());
    		Solve(rt);
    	}
    	to_ans(x,1);
    }
    void Change(int x,bool f){
    	f?(num--):(num++);
    	to_ans(x,0);
    	f?c[x].erase(0):c[x].push(0);
    	to_ans(x,1);
    	for(int i=x;prt[i];i=prt[i]){
    		to_ans(prt[i],0);
    		if(up[i].size())c[prt[i]].erase(up[i].top());
    		f?up[i].erase(dis(x,prt[i])):up[i].push(dis(x,prt[i]));
    		if(up[i].size())c[prt[i]].push(up[i].top());
    		to_ans(prt[i],1);
    	}
    }
    int main(){
    	num=n=Getint();
    	for(int i=1;i<n;i++){
    		int x=Getint(),y=Getint();
    		AddEdge(x,y),AddEdge(y,x);
    	}
    	dep[1]=1,Dfs1(1),Dfs2(1,1);
    	sum=n,mx[0]=n+1;
    	Get_size(1,0),Get_root(1,0);
    	Solve(rt);
    	int m=Getint();
    	for(int i=1;i<=m;i++){
    		char ch=getchar();
    		while(ch!='C'&&ch!='G')ch=getchar();
    		if(ch=='C'){
    			int x=Getint();
    			light[x]^=1;
    			Change(x,light[x]);
    		}else{
    			if(!num)cout<<"-1
    ";
    			else if(num==1)cout<<"0
    ";
    			else cout<<ans.top()<<'
    ';
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    shell中的$()、${}、$(())、(())
    阿拉伯数字转中文大写数字的JS
    Oracle创建新用户并将某一用户的表导进来
    便当
    登陆weblogic后页面控制台卡主
    weblogic启动错误 Unrecognized option: -jrockit
    Linux静默安装weblogic
    在vim下按ctrl+s后界面卡住
    使用SQL语句从数据库一个表中随机获取数据
    查询json数据结构的8种方式
  • 原文地址:https://www.cnblogs.com/Emiya-wjk/p/10178297.html
Copyright © 2011-2022 走看看