[CSU 1322 ZY‘s new company] 线段树维护BFS序

题目

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1322

分析

线段树维护BFS序

一个点的c级子孙在BFS序中是连续的一段,所以考虑用线段树维护BFS序

找b的c级子孙所在的区间只要在这个区间中二分,然后jump到b深度的祖先,再比较BFS序即可

区间异或和区间求和可以通过在线段树中记录每一位上出现了几个1来实现

注意一下细节就好

时间复杂度O(NlogN+M(logNlogN+logNlogAns)

代码

/**************************************************
 *        Problem:  CSU 1322
 *         Author:  clavichord93
 *          State:  Accepted
 **************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

template <class T>
inline void gmin(T &a, T b) {
    if (a > b) {
        a = b;
    }
}

template <class T>
inline void gmax(T &a, T b) {
    if (a < b) {
        a = b;
    }
}

const int MAX_N = 100005;
const int MAX_E = 100005;

struct Edge {
    int dest;
    Edge *next;
    Edge() {}
    Edge(int _dest, Edge *_next)
    : dest(_dest), next(_next) {}
};

int n, q;

Edge EdgePool[MAX_E];
Edge *EP;
Edge *e[MAX_N];

int tag[MAX_N << 2];
int cnt[MAX_N << 2][30];

int value[MAX_N];
int ancestor[MAX_N][21];

int queue[MAX_N];
int start[MAX_N];
int end[MAX_N];
int depth[MAX_N];
int entry[MAX_N];

inline void addedge(int a, int b) {
    e[a] = new(EP++)Edge(b, e[a]);
}

int getAncestor(int a, int dist) {
    for (int i = 20; i >= 0; i--) {
        if (dist & (1 << i)) {
            a = ancestor[a][i];
        }
    }
    return a;
}

#define lch(t) (t << 1)
#define rch(t) (t << 1 | 1)

void makeTree(int t, int l, int r) {
    if (l == r) {
        for (int i = 0; i < 30; i++) {
            cnt[t][i] = ((value[queue[l]] >> i) & 1);
        }
        tag[t] = 0;
    }
    else {
        int mid = (l + r) >> 1;
        makeTree(lch(t), l, mid);
        makeTree(rch(t), mid + 1, r);
        for (int i = 0; i < 30; i++) {
            cnt[t][i] = cnt[lch(t)][i] + cnt[rch(t)][i];
        }
        tag[t] = 0;
    }
}

void pushdown(int t, int l, int r) {
    if (tag[t]) {
        int mid = (l + r) >> 1;
        int lt = lch(t);
        int rt = rch(t);

        for (int i = 0; i < 30; i++) {
            if (tag[t] & (1 << i)) {
                cnt[lt][i] = (mid - l + 1) - cnt[lt][i];
                cnt[rt][i] = (r - mid) - cnt[rt][i];
            }
        }
        tag[lt] ^= tag[t];
        tag[rt] ^= tag[t];

        tag[t] = 0;
    }
}

void change(int t, int l, int r, int x, int y, int val) {
    if (x <= l && r <= y) {
        for (int i = 0; i < 30; i++) {
            if (val & (1 << i)) {
                cnt[t][i] = (r - l + 1) - cnt[t][i];
            }
        }
        tag[t] ^= val;
    }
    else {
        pushdown(t, l, r);
        int mid = (l + r) >> 1;
        if (x <= mid) {
            change(lch(t), l, mid, x, y, val);
        }
        if (y > mid) {
            change(rch(t), mid + 1, r, x, y, val);
        }
        for (int i = 0; i < 30; i++) {
            cnt[t][i] = cnt[lch(t)][i] + cnt[rch(t)][i];
        }
    }
}

long long getAns(int t, int l, int r, int x, int y) {
    if (x <= l && r <= y) {
        long long ret = 0;
        for (int i = 0; i < 30; i++) {
            ret += ((long long)cnt[t][i] << i);
        }
        return ret;
    }
    else {
        pushdown(t, l, r);
        int mid = (l + r) >> 1;
        long long ret = 0;
        if (x <= mid) {
            ret += getAns(lch(t), l, mid, x, y);
        }
        if (y > mid) {
            ret += getAns(rch(t), mid + 1, r, x, y);
        }
        return ret;
    }
}

#undef lch
#undef rch

int main() {
    #ifdef LOCAL_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    #endif
    while (scanf("%d %d", &n, &q) != EOF) {
        EP = EdgePool;
        memset(e, 0, sizeof(e));
        memset(ancestor, 0, sizeof(ancestor));
        memset(start, 0x3f, sizeof(start));
        memset(end, 0, sizeof(end));
        memset(depth, 0, sizeof(depth));
        memset(entry, 0, sizeof(entry));

        n++;
        for (int i = 2; i <= n; i++) {
            scanf("%d %d", &ancestor[i][0], &value[i]);
            ancestor[i][0]++;
            addedge(ancestor[i][0], i);
        }
        
        int tail = 0;
        queue[++tail] = 1;
        depth[1] = 1;
        for (int head = 1; head <= tail; head++) {
            int i = queue[head];
            entry[i] = head;
            gmin(start[depth[i]], head);
            gmax(end[depth[i]], head);
            for (Edge *j = e[i]; j; j = j->next) {
                depth[j->dest] = depth[i] + 1;
                queue[++tail] = j->dest;
            }
        }
        for (int j = 1; j <= 20; j++) {
            for (int i = 1; i <= n; i++) {
                ancestor[i][j] = ancestor[ancestor[i][j - 1]][j - 1];
            }
        }

        //for (int i = 1; i <= n; i++) {
            //printf("Depth = %d, Entry = %d\n", depth[i], entry[i]);
        //}

        makeTree(1, 1, n);

        for (int i = 0; i < q; i++) {
            int op, b, c, v;
            scanf("%d %d %d", &op, &b, &c);
            if (op == 0) {
                scanf("%d", &v);
            }

            b++;
            int d = c + depth[b];

            if (d > n || start[d] == 0) {
                if (op == 1) {
                    printf("-1\n");
                }
                continue;
            }

            int x, y;
            {
                int l = start[d], r = end[d];
                int ans = end[d] + 1;
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (entry[getAncestor(queue[mid], c)] >= entry[b]) {
                        ans = mid;
                        r = mid - 1;
                    }
                    else {
                        l = mid + 1;
                    }
                }
                x = ans;
            }

            {
                int l = start[d], r = end[d];
                int ans = end[d] + 1;
                while (l <= r) {
                    int mid = (l + r) >> 1;
                    if (entry[getAncestor(queue[mid], c)] > entry[b]) {
                        ans = mid;
                        r = mid - 1;
                    }
                    else {
                        l = mid + 1;
                    }
                }
                y = ans - 1;
            }

            //printf("X = %d, Y = %d\n", x, y);

            if (y < x) {
                if (op) {
                    printf("-1\n");
                }
                continue;
            }

            if (op == 0) {
                change(1, 1, n, x, y, v);
            }
            else {
                printf("%lld\n", getAns(1, 1, n, x, y));
            }
        }
    }

    return 0;
}


你可能感兴趣的:([CSU 1322 ZY‘s new company] 线段树维护BFS序)