「BZOJ1095」「ZJOI2007」Hide 捉迷藏

Description

  Jiajia 和 Wind 是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia 、Wind 和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由 N 个屋子和 N1 条双向走廊组成,这 N1 条走廊的分布使得任意两个屋子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia 负责找,而 Wind 负责操纵这 N 个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性, Jiajia 希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange)i 改变第 i 个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。

Input

  第一行包含一个整数 N ,表示房间的个数,房间将被编号为 1,2,3,,N 的整数。接下来 N1 行每行两个整数 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% 的数据, N105,M5×105

题解

动态点分治。
首先处理出所有点到所有分治根节点的距离 dis[ dfn[i][j] ][ j ] ,按照 dfs 序插入到每个分治根节点对应的动态开点线段树中。(这是为了方便查询该节点属于分治根节点的哪一个子树)

然后对于每一个分治根节点 root ,经过该节点的路径长度最大值为:

0, open[i]=1,max1i<l[mx],r[mx]<isize[root]]{dis[i][rt]}=0max1isize[root]{dis[i][rt]}+max1i<l[mx],r[mx]<isize[root]]{dis[i][rt]}, otherwise

其中 mx 为最大值所处下标, l[x] 表示 x 所处子树在 dfs 序上的左端点, r[x] 表示 x 所处子树在 dfs 序上的右端点。

上式的意思是如果 rt 开着并且只有一个子树有关的灯,那么就没有路径经过 rt 。其他情况就是以 rt 为分治根的子树距离的最大值 + 不在该最大值节点所在子树的节点距离的最大值。

然后修改 x 的时候就可以遍历所有的包含节点 x 的分治子树的根节点,修改 x 在线段树上的存在性(如果关灯则加入 x , 开灯则删除 x ,即为讲 x 所在的下标的值置为 inf ),然后更新该分治根节点的答案。

查询的时候可以再开一颗线段树,存储每个分治根节点的答案,单点修改,查询 1n 的最大值(好像也可以用手写堆)

复杂度 O((n+m)log22n)

My Code

代码很长(共 8KB),写的时候要注意细节和边界情况。当然我的代码有一些地方可以简化。
不要犯一些制杖性错误。

/**************************************************************
    Problem: 1095
    User: infinityedge
    Language: C++
    Result: Accepted
    Time:32113 ms
    Memory:214388 kb
****************************************************************/

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <complex>

#define inf 0x3f3f3f3f
#define eps 1e-10

using namespace std;
typedef long long ll;
typedef pair<int, int> P;

struct edge {
    int to, w, nxt;
} e[200005];

int h[100005], cnt;

void addedge(int x, int y) {
    cnt++; e[cnt].to = y; e[cnt].nxt = h[x]; h[x] = cnt;
    cnt++; e[cnt].to = x; e[cnt].nxt = h[y]; h[y] = cnt;
}

int n, m;

int vis[100005], siz[100005], dep[100005], tp[100005], ans[100005], Ans[100005], dis[100005][17], dfn[100005][17], root[100005];
int b[100005], Dfn[100005], end[100005], Ct, cnt_open;
vector<int> vec[100005];
int N, rt, ct, ansroot;

struct node{
    int l, r, lc, rc;
    P dat;
}d[100005 * 20 * 2 * 2];

int seg_sz;

void pushup(int k){
    d[k].dat = make_pair(-inf, 0);
    if(d[k].lc) d[k].dat = d[d[k].lc].dat;
    if(d[k].rc) {
        if(d[d[k].rc].dat.first > d[k].dat.first) d[k].dat = d[d[k].rc].dat;
    }
}

void ins(int &k, int l, int r, int pos, int x){
    if(k == 0) k = ++seg_sz;
    d[k].l = l, d[k].r = r;
    if(l == r) {
        d[k].dat = make_pair(x, pos);
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) ins(d[k].lc, l, mid, pos, x);
    else ins(d[k].rc, mid + 1, r, pos, x);
    pushup(k);
}

void modify(int k, int pos, int x){
    if(k == 0) return;
    if(d[k].l == d[k].r){
        d[k].dat = make_pair(x, pos);
        return;
    }
    int mid = (d[k].l + d[k].r) >> 1;
    if(pos <= mid) modify(d[k].lc, pos, x);
    else modify(d[k].rc, pos, x);
    pushup(k);
}

P query(int k, int l, int r){
    if(k == 0) return make_pair(-inf, 0);
    if(l <= d[k].l && d[k].r <= r){
        return d[k].dat;
    }
    int mid = (d[k].l + d[k].r) >> 1;
    P sum = make_pair(-inf, 0);
    if(l <= mid) {
        P tmp = query(d[k].lc, l, r);
        if(tmp.first > sum.first) sum = tmp;
    }
    if(r > mid) {
        P tmp = query(d[k].rc, l, r);
        if(tmp.first > sum.first) sum = tmp;
    }
    return sum; 
}



void dfs_root(int x, int f){
    siz[x] = 1; int mx = 0;
    for(int i = h[x]; i; i = e[i].nxt){
        if(e[i].to == f || vis[e[i].to]) continue;
        dfs_root(e[i].to, x);
        mx = max(mx, siz[e[i].to]);
        siz[x] += siz[e[i].to];
    }
    if(max(mx, N - siz[x] - 1) <= N / 2) rt = x;
}

void dfs_size(int x, int f){
    siz[x] = 1;
    for(int i = h[x]; i; i = e[i].nxt){
        if(e[i].to == f || vis[e[i].to]) continue;
        dfs_size(e[i].to, x);
        siz[x] += siz[e[i].to];
    }
}

void dfs_tag(int x, int f, int de){
    dep[x] = de;
    for(int i = h[x]; i; i = e[i].nxt){
        if(e[i].to == f || vis[e[i].to]) continue;
        tp[e[i].to] = rt;
        dfs_tag(e[i].to, x, de);
    }
}

void dfs_ans(int x, int f){
    dis[x][dep[x]] = dis[f][dep[x]] + 1;
    dfn[x][dep[x]] = ++ct;
    ins(root[rt], 1, N, dfn[x][dep[x]], dis[x][dep[x]]);
    for(int i = h[x]; i; i = e[i].nxt){
        if(e[i].to == f || vis[e[i].to]) continue;
        dfs_ans(e[i].to, x);
    }
}

void solve(int x, int cur){
    dfs_root(x, 0);
    Dfn[rt] = end[rt] = ++Ct;
    dfs_size(rt, 0);
    dfs_tag(rt, 0, cur);
    ins(root[rt], 1, N, 1, 0);
    ct = 1;
    for(int i = h[rt]; i; i = e[i].nxt){
        if(vis[e[i].to]) continue;
        vec[rt].push_back(ct);
        dfs_ans(e[i].to, rt);
    }
    vec[rt].push_back(ct + 1);
    P r1 = query(root[rt], 1, N);
    int r = lower_bound(vec[rt].begin(), vec[rt].end(), r1.second) - vec[rt].begin();
    int l = r - 1;
    l = vec[rt][l], r = vec[rt][r];
    P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
    if(l >= 1) r2 = query(root[rt], 1, l);
    if(r < N) r3 = query(root[rt], r + 1, N);
    if(r3.first > r2.first) r2 = r3;
    Ans[rt] = ans[rt] = r1.first + r2.first;
    vis[rt] = 1;
    int trt = rt;
    for(int i = h[trt]; i; i = e[i].nxt){
        if(vis[e[i].to]) continue;
        if(siz[e[i].to] == 1) continue;
        N = siz[e[i].to];
        solve(e[i].to, cur + 1);
        Ans[trt] = max(Ans[trt], Ans[e[i].to]);
        end[trt] = Ct;
    }
    ins(ansroot, 1, n, Dfn[trt], Ans[trt]);
}

void solvemodify(int x){
    if(b[x] == 0){
        b[x] = 1; cnt_open --;
        int mxdep = dep[x], rtp = tp[x];
        if(Dfn[x]) {
            mxdep--;
//          printf("%d ", Ans[x]);
            modify(root[x], 1, -inf);
            N = d[root[x]].r;
            P r1 = query(root[x], 1, N);
            int r = lower_bound(vec[x].begin(), vec[x].end(), r1.second) - vec[x].begin();
            int l = r - 1;
            l = vec[x][l], r = vec[x][r];
            P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
            if(l >= 1) r2 = query(root[x], 1, l);
            if(r < N) r3 = query(root[x], r + 1, N);
            if(r3.first > r2.first) r2 = r3;
            if(b[x] == 1 && r2.first == 0) r1.first = 0; 
            Ans[x] = ans[x] = r1.first + r2.first;
            modify(ansroot, Dfn[x], Ans[x]);
//          printf("%d\n", Ans[x]);
        }
        for(int i = mxdep; i >= 0; i --){
//          printf("%d ", Ans[rtp]);
            modify(root[rtp], dfn[x][i], 0);
            N = d[root[rtp]].r;
            P r1 = query(root[rtp], 1, N);
            int r = lower_bound(vec[rtp].begin(), vec[rtp].end(), r1.second) - vec[rtp].begin();
            int l = r - 1;
            l = vec[rtp][l], r = vec[rtp][r];
            P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
            if(l >= 1) r2 = query(root[rtp], 1, l);
            if(r < N) r3 = query(root[rtp], r + 1, N);
            if(r3.first > r2.first) r2 = r3;
            if(b[rtp] == 1 && r2.first == 0) r1.first = 0; 
            ans[rtp] = r1.first + r2.first;
//          printf("%d %d %d %d ", r1.first, r1.second, r2.first, r2.second);
            modify(ansroot, Dfn[rtp], ans[rtp]);
            Ans[rtp] = query(ansroot, Dfn[rtp], end[rtp]).first;
//          printf("%d\n", Ans[rtp]);
            rtp = tp[rtp];
        }
    }else{
        b[x] = 0; cnt_open ++;
        int mxdep = dep[x], rtp = tp[x];
        if(Dfn[x]) {
            mxdep--;
//          printf("%d ", Ans[x]);
            modify(root[x], 1, 0);
            N = d[root[x]].r;
            P r1 = query(root[x], 1, N);
            int r = lower_bound(vec[x].begin(), vec[x].end(), r1.second) - vec[x].begin();
            int l = r - 1;
            l = vec[x][l], r = vec[x][r];
            P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
            if(l >= 1) r2 = query(root[x], 1, l);
            if(r < N) r3 = query(root[x], r + 1, N);
            if(r3.first > r2.first) r2 = r3;
            if(b[x] == 1 && r2.first == 0) r1.first = 0; 
            Ans[x] = ans[x] = r1.first + r2.first;
            modify(ansroot, Dfn[x], Ans[x]);
//          printf("%d\n", Ans[x]);
        }
        for(int i = mxdep; i >= 0; i --){
//          printf("%d ", Ans[rtp]);
            modify(root[rtp], dfn[x][i], dis[x][i]);
            N = d[root[rtp]].r;
            P r1 = query(root[rtp], 1, N);
            int r = lower_bound(vec[rtp].begin(), vec[rtp].end(), r1.second) - vec[rtp].begin();
            int l = r - 1;
            l = vec[rtp][l], r = vec[rtp][r];
            P r2 = make_pair(-inf, 0), r3 = make_pair(-inf, 0);
            if(l >= 1) r2 = query(root[rtp], 1, l);
            if(r < N) r3 = query(root[rtp], r + 1, N);
            if(r3.first > r2.first) r2 = r3;
            if(b[rtp] == 1 && r2.first == 0) r1.first = 0; 
            ans[rtp] = r1.first + r2.first;
//          printf("%d %d %d %d ", r1.first, r1.second, r2.first, r2.second);
            modify(ansroot, Dfn[rtp], ans[rtp]);
            Ans[rtp] = query(ansroot, Dfn[rtp], end[rtp]).first;
//          printf("%d\n", Ans[rtp]);
            rtp = tp[rtp];
        }
    }
}
int main() {
    //  freopen("test.in", "r", stdin);
    //  freopen("test.out", "w", stdout);
    scanf("%d", &n);
    for (int i = 1; i < n; i ++) {
        int x, y;
        scanf("%d%d", &x, &y);
        addedge(x, y);
    }
    N = n; cnt_open = n;
    solve(1, 0);
    scanf("%d", &m);
    char ch[5];
    for(int i = 1; i <= m; i ++){
        scanf("%s", ch);
        if(ch[0] == 'G'){
            if(cnt_open == 1){
                printf("0\n");
                continue;
            }
            if(cnt_open == 0){
                printf("-1\n");
                continue;
            }
            printf("%d\n", query(ansroot, 1, n).first); 
        }else{
            int x;
            scanf("%d", &x);
            solvemodify(x);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/infinity_edge/article/details/78851937