1095: [ZJOI2007]Hide 捉迷藏
Time Limit: 40 Sec Memory Limit: 256 MB
Submit: 4152 Solved: 1756
[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。
题解
啊总算A了这道动态点分治了, 感觉点分树这个名字好高大上的样子…
相比于原来的点分, 动态点分治是建了一棵点分树, 每个重心向它子树里下一层重心连边, 就成了一棵点分树, 感觉跟支配树的构造有点相似. 由于重心所以树高是log级别的, 所以暴力跳支配树fa.
第一次写引用了黄学长的代码…
顺便粘一下hzwer的题解.
一开始写的可并堆感觉自己快炸了…
其实这种做法不难。。。就是代码长。。。
把每次分治的重心连成一棵树,树的深度是logn,每次修改一个结点只影响它到树根的一条链
这题具体实现的时候要维护三层堆
C.每个重心存所有子树到其距离
B.每个重心存各个子树最大值,即子结点堆C的最大值
A.全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和
树上距离用rmq来求比较优越2333
代码还是很清晰的, 虽然有180行….
#include<stdio.h>
#include<queue>
#include<algorithm>
#define Boc register char
#define Acce register int
#define Prio priority_queue<int>
using namespace std;
const int P = 22;
const int inf = 1e9 + 7;
const int maxn = 1e5 + 5;
const int dblmaxn = 2e5 + 10;
int n, num, tot, idx, sum, root, T;
char ss[2];
bool vis[maxn], sta[maxn];
int st[P][dblmaxn], lg[dblmaxn], in[maxn], h[maxn], dep[maxn], f[maxn], fa[maxn], siz[maxn], pw[P];
inline const int read()
{
Acce x = 0;
Boc ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
struct edge{ int nxt, v; }e[dblmaxn];
struct heap
{
int fir, sec;
Prio A, B;
inline void push(int x) { A.push(x); }
inline void erase(int x) { B.push(x); }
inline void pop()
{
while(B.size() && A.top() == B.top())
A.pop(), B.pop();
A.pop();
}
inline int top()
{
while(B.size() && A.top() == B.top())
A.pop(), B.pop();
return (A.size()) ? A.top() : 0;
}
inline int size() { return A.size() - B.size();}
inline int stop()
{
if (size() < 2) return 0;
fir = top(); pop();
sec = top(); push(fir);
return sec;
}
}A, B[maxn], C[maxn];
inline void add(int u, int v)
{
e[++ num].v = v, e[num].nxt = h[u], h[u] = num;
e[++ num].v = u, e[num].nxt = h[v], h[v] = num;
}
void dfs(int u, int tfa)
{
in[u] = ++ idx;
st[0][idx] = dep[u];
for (int i = h[u]; i; i = e[i].nxt)
{
if (e[i].v == tfa) continue;
dep[e[i].v] = dep[u] + 1;
dfs(e[i].v, u);
st[0][++ idx] = dep[u];
}
}
void getrt(int u, int tfa)
{
siz[u] = 1, f[u] = 0;
for (int i = h[u]; i; i = e[i].nxt)
{
if (e[i].v == tfa || vis[e[i].v]) continue;
getrt(e[i].v, u);
siz[u] += siz[e[i].v];
f[u] = max(f[u], siz[e[i].v]);
}
f[u] = max(f[u], sum - siz[u]);
if (f[u] < f[root]) root = u;
}
void divi(int u, int dfa)
{
fa[u] = dfa, vis[u] = true;
for (int i = h[u]; i; i = e[i].nxt)
{
if (vis[e[i].v]) continue;
sum = siz[e[i].v], root = 0;
getrt(e[i].v, u), divi(root, u);
}
}
inline int query(int u, int v)
{
u = in[u], v = in[v];
if (u > v) swap(u, v);
int len = lg[v - u + 1];
return min(st[len][u], st[len][v - pw[len] + 1]);
}
inline int dis(int u, int v)
{ return dep[u] + dep[v] - 2 * query(u, v); }
inline void turn_off(int u)
{
B[u].push(0);
if (B[u].size() == 2) A.push(B[u].top());
int v = u;
while (fa[u])
{
int f = fa[u], D = dis(f, v), tmp = C[u].top();
C[u].push(D);
if (D > tmp)
{
int mx = B[f].top() + B[f].stop(), size = B[f].size();
if (tmp) B[f].erase(tmp);
B[f].push(D);
int now = B[f].top() + B[f].stop();
if (now > mx)
{
if (size >= 2) A.erase(mx); //means mx has contributed to A
if (B[f].size() >= 2) A.push(now); //now
}
}
u = f;
}
}
inline void turn_on(int u)
{
if (B[u].size() == 2) A.erase(B[u].top());
B[u].erase(0);
int v = u;
while (fa[u])
{
int f = fa[u], D = dis(f, v), tmp = C[u].top();
C[u].erase(D);
if (D == tmp)
{
int mx = B[f].top() + B[f].stop(), size = B[f].size();
B[f].erase(D);
if(C[u].top()) B[f].push(C[u].top());
int now = B[f].top() + B[f].stop();
if(now < mx)
{
if(size >= 2) A.erase(mx);
if(B[f].size() >= 2) A.push(now);
}
}
u = f;
}
}
inline void init()
{
pw[0] = 1;
for (int i = 1; i < P; ++ i) pw[i] = pw[i - 1] << 1;
lg[0] = -1;
for (int i = 1; i < dblmaxn; ++ i) lg[i] = lg[i >> 1] + 1;
}
int main()
{
init();
n = read();
int u, v;
for (Acce i = 1; i < n; ++ i)
u = read(), v = read(), add(u, v);
dfs(1, 0);
for (Acce i = 1; i <= lg[idx]; ++ i)
for (Acce j = 1; j + pw[i] - 1 <= idx; ++ j)
st[i][j] = min(st[i - 1][j], st[i - 1][j + pw[i - 1]]);
f[root = 0] = inf, sum = n;
getrt(1, 0), divi(root, 0);
for (Acce i = 1; i <= n; ++ i) C[i].push(0);
for (Acce i = 1; i <= n; ++ i) turn_off(i), tot ++;
T = read();
for (Acce i = 1; i <= T; ++ i)
{
scanf("%s", ss);
if (ss[0] == 'C')
{
int x = read();
if (sta[x]) turn_off(x), tot ++;
else turn_on(x), tot --;
sta[x] ^= 1;
} else
{
if(tot <= 1) printf("%d\n", tot - 1);
else printf("%d\n", A.top());
}
}
}