GXOI/GZOI2019-旧词

相关链接(雾:[LNOI2014]LCA

实际上这题就是加了一个幂。。原题爆破比赛

原题:当$k=1$时

暴力:求LCA再求深度。。然后观察一下求LCA的方法。。最暴力的方法就是把根节点到节点$i$的路径上的点都打上标记,然后由节点$y$往上,直到一个有标记的点为止。。

然而这题并不需要求LCA的序号,只需要深度,于是对于每个询问中$[1,x]$的每个节点$i$,把上面打标记换成权值$+1$,把扫到一个有标记的点为止变为统计根节点到节点$y$的路径上节点的权值和。。

然后我们发现每个询问中中的节点可以一起做,于是这就变成了树链剖分的模版。。

当$k\not=1$时

先观察$k=1$时,点的权值其实是$(dep_i)^1-(dep_i-1)^1=1$

于是,当$k\not=1$时,点权就是$(dep_i)^k-(dep_i-1)^k=1$。当然,处理这个的时候要预处理一下。。其他的和$k=1$时一样。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <bits/stdc++.h>
#define lson (n << 1)
#define rson (n << 1 | 1)
#define next \
___________________________________________________________________________________________________
using namespace std;

const int MAXN = 50004, MOD = 998244353;
int n, q, K, f[MAXN], x, y, value[MAXN], size[MAXN], h, head[MAXN], dep[MAXN],
v[MAXN], cnt, t[MAXN << 2], k[MAXN << 2], delta[MAXN << 2], id[MAXN],
nid[MAXN], top[MAXN], son[MAXN], ans[MAXN];

struct edge {
int to, next;
} g[MAXN << 1];

struct data {
int x, y, id;
} s[MAXN];

inline void addedge(int x, int y) {
g[++h].next = head[x], head[x] = h, g[h].to = y;
}

inline int qpow(int a, int b) {
int s = 1;
while (b) {
if (b & 1)
s = 1LL * s * a % MOD;
a = 1LL * a * a % MOD, b >>= 1;
}
return s;
}

inline void pushdown(int n) {
int x = delta[n];
delta[n] = 0, t[lson] = (t[lson] + 1LL * x * k[lson]) % MOD,
t[rson] = (t[rson] + 1LL * x * k[rson]) % MOD,
delta[lson] = (delta[lson] + x) % MOD, delta[rson] = (delta[rson] + x) % MOD;
}

inline void dfs1(int x) {
int j, maxs = -1;
size[x] = 1;
for (int i = head[x]; i; i = g[i].next) {
j = g[i].to;
if (dep[j])
continue;
dep[j] = dep[x] + 1, dfs1(j), size[x] += size[j];
if (size[j] >= maxs)
son[x] = j, maxs = size[j];
}
}

inline void dfs2(int x, int ttop) {
top[x] = ttop, id[x] = ++cnt, nid[cnt] = x;
if (!son[x])
return;
dfs2(son[x], ttop);
int j;
for (int i = head[x]; i; i = g[i].next) {
j = g[i].to;
if (j == son[x] || j == f[x])
continue;
dfs2(j, j);
}
}

inline bool cmp(data a, data b) { return a.x < b.x; }

inline int add(int x, int y) {
x += y;
if (x >= MOD)
x -= MOD;
return x;
}

inline void build(int n, int l, int r) {
if (l == r)
return (void)(k[n] = v[nid[l]], t[n] = delta[n] = 0);
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r), t[n] = add(t[lson], t[rson]),
k[n] = add(k[lson], k[rson]);
}

inline int query(int n, int l, int r, int ll, int rr) {
if (ll <= l && r <= rr)
return t[n];
int mid = (l + r) >> 1, ans = 0;
if (delta[n])
pushdown(n);
if (ll <= mid)
ans = query(lson, l, mid, ll, rr);
if (rr > mid)
ans = add(ans, query(rson, mid + 1, r, ll, rr));
return ans;
}

inline void update(int n, int l, int r, int ll, int rr) {
if (ll <= l && r <= rr)
return (void)(t[n] = add(t[n], k[n]), delta[n] = add(delta[n], 1));
int mid = (l + r) >> 1;
if (delta[n])
pushdown(n);
if (ll <= mid)
update(lson, l, mid, ll, rr);
if (rr > mid)
update(rson, mid + 1, r, ll, rr);
t[n] = add(t[lson], t[rson]);
}

inline void change(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] > dep[top[y]])
swap(x, y);
update(1, 1, n, id[top[y]], id[y]), y = f[top[y]];
}
if (dep[x] > dep[y])
swap(x, y);
update(1, 1, n, id[x], id[y]);
}

int solve(int x, int y) {
int ans = 0;
while (top[x] != top[y]) {
if (dep[top[x]] > dep[top[y]])
swap(x, y);
ans = add(ans, query(1, 1, n, id[top[y]], id[y])), y = f[top[y]];
}
if (dep[x] > dep[y])
swap(x, y);
ans = add(ans, query(1, 1, n, id[x], id[y]));
return ans;
}

int main() {
scanf("%d%d%d", &n, &q, &K);
for (int i = 2; i <= n; ++i)
scanf("%d", &f[i]), addedge(f[i], i);
dep[1] = 1, dfs1(1), dfs2(1, 1);
for (int i = 1; i <= n; ++i)
value[i] = qpow(dep[i], K);
for (int i = 1; i <= n; ++i)
v[i] = (value[i] - value[f[i]] + MOD) % MOD;
for (int i = 1; i <= q; ++i)
scanf("%d%d", &s[i].x, &s[i].y), s[i].id = i;
sort(s + 1, s + 1 + q, cmp), build(1, 1, n);
int l = 1;
for (int i = 1; i <= q; ++i) {
while (l <= s[i].x && l <= n)
change(1, l), l++;
ans[s[i].id] = solve(1, s[i].y);
}
for (int i = 1; i <= q; ++i)
printf("%d\n", ans[i]);
return 0;
}

   转载规则


《GXOI/GZOI2019-旧词》 VinovnyyPoterpevshiy 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
GXOI/GZOI2019-lvxingzhe GXOI/GZOI2019-lvxingzhe
暴力:对于每个特殊点为起始点计算Dijkstra或spfa。。 然而这样有很多重复操作,很多路径会被重复走。 改善:考虑把特殊点分组,分组只计算两组间的最短路,组内不计算。显然,分为两组最优(如果分为多组的话其实和没有分组一样会走重复路径)
2019-09-22
下一篇 
CF55E-Very-Simple-Problem CF55E-Very-Simple-Problem
讲道理的话,题目中有simple一词的题目都不会简单。。 这道题如果我们直接计算包含的个数,本蒟蒻只能想到$O(n^3)$的解法,然后就咕咕了。。于是我们可以从反面考虑——数不包含该点的三角形。然后我们发现,如果一个三角形不包含该点,则这个
2019-09-22
  目录