[ZJOI 2007]Hide 捉迷藏

Posted NaVi_Awson

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ZJOI 2007]Hide 捉迷藏相关的知识,希望对你有一定的参考价值。

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。

题解

博主吃鸡中...莫慌...一定补上...

  1 //It is made by Awson on 2018.1.6
  2 #include <set>
  3 #include <map>
  4 #include <cmath>
  5 #include <ctime>
  6 #include <queue> 
  7 #include <stack>
  8 #include <cstdio>
  9 #include <string>
 10 #include <vector>
 11 #include <cstdlib>
 12 #include <cstring>
 13 #include <iostream>
 14 #include <algorithm>
 15 #define LL long long
 16 #define RE register
 17 #define lowbit(x) ((x)&(-(x)))
 18 #define Max(a, b) ((a) > (b) ? (a) : (b))
 19 #define Min(a, b) ((a) < (b) ? (a) : (b))
 20 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
 21 using namespace std;
 22 const int N = 100000;
 23 const int M = 500000;
 24 const int INF = ~0u>>1;
 25  
 26 int n, m, u, v, fa[N+5], light[N+5];
 27 char ch[5];
 28 struct tt {
 29     int to, next;
 30 }edge[(N<<1)+5];
 31 int path[N+5], top;
 32 void add(int u, int v) {
 33     edge[++top].to = v;
 34     edge[top].next = path[u];
 35     path[u] = top;
 36 }
 37 namespace LCA {
 38     int bin[25], lim, dep[N+5], fa[N+5][25];
 39     void dfs(int o, int depth, int father) {
 40         fa[o][0] = father, dep[o] = depth; 
 41         for (int i = path[o]; i; i = edge[i].next)
 42             if (edge[i].to != father) dfs(edge[i].to, depth+1, o);
 43     }
 44     int query(int x, int y) {
 45         if (dep[x] < dep[y]) Swap(x, y);
 46         for (int i = lim; i >= 0; i--) if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
 47         if (x == y) return x;
 48         for (int i = lim; i >= 0; i--) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
 49         return fa[x][0];
 50     }
 51     int dist(int x, int y) {return dep[x]+dep[y]-(dep[query(x, y)]<<1); }
 52     void main() {
 53         lim = log(n)/log(2), bin[0] = 1; for (int i = 1; i <= 20; i++) bin[i] = bin[i-1]<<1;
 54         dfs(1, 1, 0);
 55         for (int t = 1; t <= lim; t++) for (int i = 1; i <= n; i++) fa[i][t] = fa[fa[i][t-1]][t-1];
 56     }
 57 }
 58 struct heap {
 59     priority_queue<int>q, p;
 60     void pop() {
 61         while (!q.empty() && !p.empty() && q.top() == p.top()) q.pop(), p.pop();
 62         q.pop();
 63     }
 64     void erase(int val) {p.push(val); }
 65     int top() {
 66         while (!q.empty() && !p.empty() && q.top() == p.top()) q.pop(), p.pop();
 67         return q.top();
 68     }
 69     int sec() {
 70         while (!q.empty() && !p.empty() && q.top() == p.top()) q.pop(), p.pop();
 71         int tmp = q.top(); q.pop();
 72         while (!q.empty() && !p.empty() && q.top() == p.top()) q.pop(), p.pop();
 73         int val = q.top();
 74         q.push(tmp); return val;
 75     }
 76     int size() {return q.size()-p.size(); }
 77     void push(int val) {q.push(val); }
 78 }q1[N+5], q2[N+5], q3;
 79 namespace Point_divide {
 80     int size[N+5], mx[N+5], vis[N+5], root, minsize;
 81     void get_size(int o, int fa) {
 82         size[o] = 1, mx[o] = 0;
 83         for (int i = path[o]; i; i = edge[i].next)
 84             if (edge[i].to != fa && !vis[edge[i].to]) {
 85                 get_size(edge[i].to, o);
 86                 size[o] += size[edge[i].to];
 87                 if (size[edge[i].to] > mx[o]) mx[o] = size[edge[i].to];
 88             }
 89     }
 90     void get_root(int o, int pa, int fa) {
 91         mx[o] = Max(mx[o], size[pa]-size[o]);
 92         if (mx[o] < minsize) minsize = mx[o], root = o;
 93         for (int i = path[o]; i; i = edge[i].next)
 94             if (edge[i].to != fa && !vis[edge[i].to]) get_root(edge[i].to, pa, o);
 95     }
 96     void get_dist(int o, int pa, int fa) {
 97         q1[root].push(LCA::dist(pa, o));
 98         for (int i = path[o]; i; i = edge[i].next)
 99             if (edge[i].to != fa && !vis[edge[i].to]) get_dist(edge[i].to, pa, o);
100     }
101     void work(int o, int pa) {
102         minsize = INF; get_size(o, 0), get_root(o, o, 0);
103         fa[root] = pa, vis[root] = 1; q2[root].push(0), q1[root].push(LCA::dist(pa, root));
104         for (int i = path[root]; i; i = edge[i].next)
105             if (!vis[edge[i].to]) get_dist(edge[i].to, pa, root);
106         q2[pa].push(q1[root].top()); int rt = root;
107         for (int i = path[root]; i; i = edge[i].next)
108             if (!vis[edge[i].to]) work(edge[i].to, rt);
109         if (q2[rt].size() >= 2) q3.push(q2[rt].top()+q2[rt].sec());
110     }
111     void main() {work(1, 0); }
112 }
113 
114 void turnon(int o) {
115     if (q2[o].size() >= 2) q3.erase(q2[o].top()+q2[o].sec());
116     q2[o].erase(0);
117     if (q2[o].size() >= 2) q3.push(q2[o].top()+q2[o].sec());
118     for (int x = o; fa[x]; x = fa[x]) {
119         if (q2[fa[x]].size() >= 2) q3.erase(q2[fa[x]].top()+q2[fa[x]].sec());
120         q2[fa[x]].erase(q1[x].top());
121         q1[x].erase(LCA::dist(o, fa[x]));
122         if (q1[x].size()) q2[fa[x]].push(q1[x].top());
123         if (q2[fa[x]].size() >= 2) q3.push(q2[fa[x]].top()+q2[fa[x]].sec());
124     }
125 }
126 void turnoff(int o) {
127     if (q2[o].size() >= 2) q3.erase(q2[o].top()+q2[o].sec());
128     q2[o].push(0);
129     if (q2[o].size() >= 2) q3.push(q2[o].top()+q2[o].sec());
130     for (int x = o; fa[x]; x = fa[x]) {
131         if (q2[fa[x]].size() >= 2) q3.erase(q2[fa[x]].top()+q2[fa[x]].sec());
132         if (q1[x].size()) q2[fa[x]].erase(q1[x].top());
133         q1[x].push(LCA::dist(fa[x], o));
134         q2[fa[x]].push(q1[x].top());
135         if (q2[fa[x]].size() >= 2) q3.push(q2[fa[x]].top()+q2[fa[x]].sec());
136     }
137 }
138 void work() {
139     scanf("%d" ,&n);
140     for (int i = 1; i < n; i++) {
141         scanf("%d%d", &u, &v);
142         add(u, v), add(v, u);
143     }
144     LCA::main(); Point_divide::main();
145     int cnt = n; scanf("%d", &m);
146     while (m--) {
147         scanf("%s", ch);
148         if (ch[0] == G) {
149             if (cnt <= 1) printf("%d\n", cnt-1);
150             else printf("%d\n", q3.top());
151         }else {
152             scanf("%d", &u);
153             if (light[u]) turnoff(u), cnt++;
154             else turnon(u), cnt--;
155             light[u] ^= 1;
156         }
157     }
158 }
159 int main() {
160     work();
161     return 0;
162 }

 

以上是关于[ZJOI 2007]Hide 捉迷藏的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ1095][ZJOI2007]Hide 捉迷藏

bzoj1095: [ZJOI2007]Hide 捉迷藏

BZOJ1095[ZJOI2007]Hide 捉迷藏 动态树分治+堆

[bzoj1095][ZJOI2007]Hide 捉迷藏 点分树,动态点分治

Bzoj1095 [ZJOI2007]Hide 捉迷藏

[ZJOI 2007]Hide 捉迷藏