[BZOJ1095][ZJOI2007]Hide 捉迷藏 动态点分治

时间:2022-02-07 09:29:19

1095: [ZJOI2007]Hide 捉迷藏

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 4330  Solved: 1818
[Submit][Status][Discuss]

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。

 

Source

 

以前看到这个算法就觉得好高深,所以一直没学。现在看来这个算法怎么这么逗啊!

先构造出点分树,然后每个节点开两个堆分别维护子树到他的所有链和他的子树到父分治节点的所有链。

再开一个全局堆维护每个节点的最大答案。

[BZOJ1095][ZJOI2007]Hide 捉迷藏 动态点分治[BZOJ1095][ZJOI2007]Hide 捉迷藏 动态点分治
  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<queue>
  8 using namespace std;
  9 #define maxn 100005
 10 int read() {
 11     int x=0,f=1;char ch=getchar();
 12     for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
 13     for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
 14     return x*f;
 15 }
 16 struct edge {
 17     int to,next;
 18 }e[maxn*2];
 19 int head[maxn],cnt;
 20 void add(int u,int v) {e[cnt].to=v;e[cnt].next=head[u];head[u]=cnt++;}
 21 struct data {
 22     priority_queue<int> q,del;
 23     void push(int x) {q.push(x);}
 24     void erase(int x) {del.push(x);}
 25     int top() {while(del.size()&&del.top()==q.top()) {del.pop();q.pop();}return q.top();}
 26     void pop() {while(del.size()&&del.top()==q.top()){del.pop();q.pop();}q.pop();}
 27     int sectop() {int tmp=top();pop();int re=top();push(tmp);return re;}
 28     int size() {return q.size()-del.size();}
 29 }c[maxn],f[maxn],ans;
 30 void insert(data &s) {if(s.size()>1) ans.push(s.top()+s.sectop());}
 31 void dele(data &s) {if(s.size()>1) ans.erase(s.top()+s.sectop());}
 32 int n;
 33 int light[maxn],vis[maxn],fa[maxn],up[maxn][25],dep[maxn];
 34 void dfs(int x,int ff) {
 35     up[x][0]=ff;
 36     for(int i=1;i<=20;i++) up[x][i]=up[up[x][i-1]][i-1];
 37     for(int i=head[x];i>=0;i=e[i].next) {
 38         int to=e[i].to;if(to==ff) continue;
 39         dep[to]=dep[x]+1;
 40         dfs(to,x);
 41     }
 42 }
 43 int findlca(int x,int y) {
 44     if(dep[x]<dep[y]) swap(x,y);
 45     int t=dep[x]-dep[y];
 46     for(int i=20;i>=0;i--) if(t&(1<<i)) x=up[x][i];
 47     for(int i=20;i>=0;i--) if(up[x][i]!=up[y][i]) x=up[x][i],y=up[y][i];
 48     return x==y?x:up[x][0];
 49 }
 50 int root,sum,fs[maxn],son[maxn];
 51 void findroot(int x,int ff) {
 52     son[x]=1;fs[x]=0;
 53     for(int i=head[x];i>=0;i=e[i].next) {
 54         int to=e[i].to;if(vis[to]||to==ff) continue;
 55         findroot(to,x);
 56         son[x]+=son[to];
 57         fs[x]=max(fs[x],son[to]);
 58     }
 59     fs[x]=max(fs[x],sum-son[x]);
 60     if(fs[x]<fs[root]) root=x;
 61 }
 62 void work(int x,int ff,int rt) {
 63     f[root].push(dep[x]+dep[rt]-2*dep[findlca(x,rt)]);
 64 //  cout<<x<<' '<<rt<<' '<<root<<' '<<dep[x]+dep[rt]-2*dep[findlca(x,rt)]<<endl;
 65     for(int i=head[x];i>=0;i=e[i].next) {
 66         int to=e[i].to;if(to==ff||vis[to]) continue;
 67         work(to,x,rt);
 68     }
 69 }
 70 void build_tree(int x,int ff) {
 71     //cout<<x<<' '<<ff<<':'<<endl;
 72     fa[x]=ff;vis[x]=1;
 73     c[x].push(0);
 74     work(x,0,ff);
 75     for(int i=head[x];i>=0;i=e[i].next) {
 76         int to=e[i].to;if(vis[to]) continue;
 77         root=0;fs[0]=214748364;sum=son[to];findroot(to,x);
 78         to=root;
 79         build_tree(root,x);
 80         c[x].push(f[to].top());
 81     }
 82     insert(c[x]);
 83 }
 84 void ton(int x) {
 85     dele(c[x]);
 86     c[x].erase(0);
 87     insert(c[x]);
 88     for(int i=x;i;i=fa[i]) {
 89         dele(c[fa[i]]);
 90         if(f[i].size()) c[fa[i]].erase(f[i].top());
 91         f[i].erase(dep[x]+dep[fa[i]]-2*dep[findlca(x,fa[i])]);
 92         if(f[i].size()) c[fa[i]].push(f[i].top());
 93         insert(c[fa[i]]);
 94     }
 95 }
 96 void toff(int x) {
 97     dele(c[x]);
 98     c[x].push(0);
 99     insert(c[x]);
100     for(int i=x;i;i=fa[i]) {
101         dele(c[fa[i]]);
102         if(f[i].size()) c[fa[i]].erase(f[i].top());
103         f[i].push(dep[x]+dep[fa[i]]-2*dep[findlca(x,fa[i])]);
104         if(f[i].size()) c[fa[i]].push(f[i].top());
105         insert(c[fa[i]]);
106     }
107 }
108 int main() {
109     //freopen("hide0.in","r",stdin);
110     memset(head,-1,sizeof(head));
111     n=read();
112     for(int i=1;i<n;i++) {
113         int x=read(),y=read();
114         add(x,y);add(y,x);
115     }
116     dfs(1,0);
117     fs[0]=214748364;root=0;sum=n;findroot(1,0);
118     build_tree(root,0);
119     int num=n;
120     int q=read();
121     while(q--) {
122         char ch[10];int x;
123         scanf("%s",ch);
124         if(ch[0]=='C') {
125             x=read();
126             if(light[x]) {toff(x);num++;light[x]=0;}
127             else {ton(x);num--;light[x]=1;}
128         }
129         else {
130             if(num<=1) printf("%d\n",num-1);
131             else printf("%d\n",ans.top());
132         }
133     }
134 }
View Code