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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章