题目传送门:https://www.luogu.com.cn/problem/P5903
树链剖分LCA
主要在于,首先要找x的k级祖先,从这个点出发不断往上找他的顶端端点,如果顶端端点所在的深度小于k级祖先所在的深度(也就是dep[x] - k),继续找他的父亲节点所在链的顶端端点,循环比较顶端端点和k级祖先所在深度,当x的顶端端点的深度大于k级祖先所在的深度时,说明所要找的祖先在这条链上,此时我们可以求得此时x节点的深度与k级祖先深度的差值,最后结果就是x节点的dfs序-差值得到k祖先的dfs序,再转换成原先序列所对应的点。
代码:
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<vector>
5 #include<map>
6 #include<queue>
7 #include<set>
8 #include<cmath>
9 #include<list>
10 #include<cstring>
11 #include<string>
12 #define ui unsigned int
13 #define ll long long
14 #define ull unsigned long long
15 #define inf 0x3f3f3f3f
16 #define inff 0x7fffffff
17 using namespace std;
18 const int N = 2000000 + 10;
19
20 int dep[N], siz[N], son[N], fa[N], top[N], dfn[N], rnk[N];
21 int w[N], ctr[N], cnt;
22 int n, q;
23
24 ui s;
25 inline ui get(ui x) {
26 x ^= x << 13;
27 x ^= x >> 17;
28 x ^= x << 5;
29 return s = x;
30 }
31
32 struct node {
33 int to, w, next;
34 }e[N << 2];
35 int head[N << 2];
36 int tot;
37
38 void add(int u, int v) {
39 //e[cnt].w = w;
40 e[tot].to = v;
41 e[tot].next = head[u];
42 head[u] = tot++;
43 }
44
45 void dfs1(int x) {
46 siz[x] = 1;
47 for (int i = head[x]; i + 1; i = e[i].next) {
48 int to = e[i].to;
49 if (to == fa[x]) continue;
50 fa[to] = x;
51 dep[to] = dep[x] + 1;
52 dfs1(to);
53 siz[x] += siz[to];
54 if (siz[to] > siz[son[x]]) son[x] = to;
55 }
56 }
57
58 void dfs2(int x, int tp) {
59 top[x] = tp;
60 dfn[x] = ++cnt;
61 rnk[cnt] = x;
62 if (son[x]) dfs2(son[x], tp);
63 for (int i = head[x]; i + 1; i = e[i].next) {
64 int to = e[i].to;
65 if (to != son[x] && to != fa[x]) dfs2(to, to);
66 }
67 //ctr[x] = cnt;
68 }
69
70 struct SegTree {
71 int sum[N << 2], lazy[N << 2];
72 void PushUp(int rt) {
73 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
74 }
75 void Build(int l, int r, int rt) {
76 if (l == r) {
77 sum[rt] = 0;
78 return;
79 }
80 int mid = (l + r) >> 1;
81 Build(l, mid, rt << 1);
82 Build(mid + 1, r, rt << 1 | 1);
83 PushUp(rt);
84 }
85 void PushDown(int rt, int ln, int rn) {
86 if (lazy[rt]) {
87 lazy[rt << 1] += lazy[rt];
88 lazy[rt << 1 | 1] += lazy[rt];
89 sum[rt << 1] += lazy[rt] * ln;
90 sum[rt << 1 | 1] += lazy[rt] * rn;
91 lazy[rt] = 0;
92 }
93 }
94 void Update(int L, int R, int C, int l, int r, int rt) {
95 if (l >= L && r <= R) {
96 sum[rt] += (C * (r - l + 1));
97 lazy[rt] += C;
98 return;
99 }
100 int m = (l + r) >> 1;
101 PushDown(rt, m - l + 1, r - m);
102 if (m >= L) Update(L, R, C, l, m, rt << 1);
103 if (m < R) Update(L, R, C, m + 1, r, rt << 1 | 1);
104 PushUp(rt);
105 }
106 int Query(int L, int R, int l, int r, int rt) {
107 if (l >= L && r <= R) {
108 return sum[rt];
109 }
110 int m = (l + r) >> 1;
111 PushDown(rt, m - l + 1, r - m);
112 int ans = 0;
113 if (m >= L) ans = (ans + Query(L, R, l, m, rt << 1));
114 if (m < R) ans = (ans + Query(L, R, m + 1, r, rt << 1 | 1));
115 return ans;
116 }
117 }st;
118
119 int rt = 1;
120
121 inline int Jump(int x, int k) {
122 int d = dep[x] - k;
123 if (d <= 0) return 1;
124 //else if (d < 0) return 1;
125 while (dep[top[x]] > d) x = fa[top[x]];
126 d = dep[x] - d; // 求当前x节点与k级祖先的深度差
127 return rnk[dfn[x] - d];
128 }
129
130 int jump(int x, int k) {
131 while (k >= dfn[x] - dfn[top[x]] + 1 && x != rt) {
132 k -= (dfn[x] - dfn[top[x]] + 1);
133 x = fa[top[x]];
134 }
135 return rnk[dfn[x] - k];
136 }
137
138 int main() {
139
140 ios::sync_with_stdio(false);
141 cin.tie(0), cout.tie(0);
142 cin >> n >> q >> s;
143 memset(head, -1, sizeof(head));
144 tot = 0;
145 for (int i = 1; i <= n; i++) {
146 int x;
147 cin >> x;
148 if (!x) rt = i;
149 else add(x, i);
150 }
151 dep[rt] = 1;
152 dfs1(rt);
153 dfs2(rt, rt);
154 st.Build(1, cnt, 1);
155 int lastans = 0;
156 ll ans = 0;
157 for (int i = 1; i <= q; i++) {
158 int x = (get(s) ^ lastans) % n + 1;
159 int k = (get(s) ^ lastans) % dep[x];
160 lastans = Jump(x, k);
161 ans ^= 1ll * i * lastans;
162 }
163 cout << ans << "\n";
164
165 return 0;
166 }