bzoj1095: [ZJOI2007]Hide 捉迷藏

来源:互联网 发布:c语言打印糖果图形 编辑:程序博客网 时间:2024/05/22 10:24

题目链接

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 100010struct 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;}
0 0
原创粉丝点击