题目
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; }