bzoj1095: [ZJOI2007]Hide 捉迷藏

题目链接

bzoj1095

题意

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。

题解

和qtree4差不多。可以用链分治,点分治或边分治。但要支持动态修改。所以就叫动态树分治。
这里介绍一下动态的点分治。就是堆套堆套堆。(边分就是堆套堆,链分就是堆套线段树)。
我们对于一个重心,将每个子树中的点到该子树的距离都存在一个堆中,记为s1。我们可以将这个堆记录在下一层的分治重心中。然后对于每个重心在记录一个堆,插入所有子树的s1中的top,记为s2。再将s2中的第一大和第二大相加,就是经过该重心的最长链,将它存在一个答案堆中。每次询问只要输出答案堆的堆顶。对于关灯就是插点,开灯就是删点。维护一下每一层的s1和s2还有答案堆就好了。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;

#define N 100010
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.top();}
    int S_top(){int tmp=Top(); Pop();int ans=Top(); Push(tmp);return ans;}
    int Size(){return A.size()-B.size();}
}s1[N],s2[N],ans;
struct edge{
    int x,next;
}e[N*2];
int first[N],tot,dis[N][20],dep[N],size[N],root,f[N],n,m,x,y,cnt;
char op;
bool v[N],b[N];

void add(int x,int y){
    e[++tot].x=y;
    e[tot].next=first[x];
    first[x]=tot;
}
void dfs(int x,int y,int s){
    size[x]=1; bool b=true;
    for(int i=first[x];i;i=e[i].next)
    if(!v[e[i].x]&&e[i].x!=y){
        dfs(e[i].x,x,s);
        size[x]+=size[e[i].x];
        if(size[e[i].x]>s/2) b=false;
    }
    if(s-size[x]>s/2) b=false;
    if(b) root=x;
}
void calc(int x,int y,int d,int id,Heap &s){
    s.Push(d);
    size[x]=1; dis[x][id]=d;
    for(int i=first[x];i;i=e[i].next)
    if(e[i].x!=y&&!v[e[i].x]){
        calc(e[i].x,x,d+1,id,s);
        size[x]+=size[e[i].x];
    }
}
int divise(int x,int y,int s){
    dfs(x,0,s);
    int rt=root; v[rt]=true;
    dep[rt]=dep[y]+1; f[rt]=y;
    s2[rt].Push(0); v[rt]=true;
    for(int i=first[rt];i;i=e[i].next)
    if(!v[e[i].x]){
        Heap tmp;
        calc(e[i].x,0,0,dep[rt]+1,tmp);
        int rec=divise(e[i].x,rt,size[e[i].x]);
        s1[rec]=tmp;
        if(tmp.Size())s2[rt].Push(tmp.Top()+1);
    }
    if(s2[rt].Size()>1) ans.Push(s2[rt].Top()+s2[rt].S_top());
    return rt; 
}
void change(int x,int k){
    if(s2[x].Size()>1)ans.Erase(s2[x].Top()+s2[x].S_top());
    if(k==0) s2[x].Erase(0); else s2[x].Push(0);
    if(s2[x].Size()>1)ans.Push(s2[x].Top()+s2[x].S_top());
    for(int i=x;f[i];i=f[i]){
        if(s2[f[i]].Size()>1) ans.Erase(s2[f[i]].Top()+s2[f[i]].S_top());
        if(s1[i].Size())s2[f[i]].Erase(s1[i].Top()+1);
        if(k==0)s1[i].Erase(dis[x][dep[i]]); else s1[i].Push(dis[x][dep[i]]);
        if(s1[i].Size()) s2[f[i]].Push(s1[i].Top()+1);
        if(s2[f[i]].Size()>1) ans.Push(s2[f[i]].Top()+s2[f[i]].S_top());
    }
}
char BUF[200001],*buf,*end;
#define getch() (buf==end?fread(BUF,1,200000,stdin),buf=BUF,end=buf+200000,*(buf++):*(buf++))
inline void read(int &x){
    static char c;
    for(c=getch();c<'0'||c>'9';c=getch());
    for(x=0;'0'<=c&&c<='9';c=getch())x=x*10+c-'0';
}
int main(){
    read(n);
    cnt=n;
    for(int i=1;i<n;i++){
        read(x); read(y);
        add(x,y); add(y,x);
    } 
    divise(1,0,n);
    read(m);
    for(int i=1;i<=m;i++){
        for(op=getch();op!='C'&&op!='G';op=getch());
        if(op=='G') {
            if(cnt>1) printf("%d\n",ans.Top());
            else if(cnt==0) puts("-1");
            else puts("0");
        }
        else {
            read(x);
            if(b[x]) cnt++,b[x]=false,change(x,1);
            else cnt--,b[x]=true,change(x,0);
        }
    }
    return 0;
}
发布了60 篇原创文章 · 获赞 8 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章