[BZOJ]1095 捉迷藏 动态点分治(点分树)

来源:互联网 发布:纸上数据如何快速录入 编辑:程序博客网 时间:2024/05/16 11:35

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());        }    }}
阅读全文
0 0
原创粉丝点击