什么都能出上仙人掌……

Description

有一棵仙人掌, 每次询问当1到该节点的所有简单路径都被封锁时, 节点能到达的所有点的权值种类中, 出现了奇数次/偶数次的有多少种.

Solution

一开始以为要圆方树搞一搞再套莫队什么的……

其实仙人掌也是可以做出一个符合要求的序列的. 一个点一定有一个父亲, 最多有一个环上的(儿子)? Tarjan可以找出来这个儿子, 我们在DFS完其他所有普通儿子后, 记录这个点的区间结尾, 然后再处理这个特殊点.

这个时候一个点记下的区间就是所有的合法点. 然后还要在DFS序上莫队, 对颜色分块……

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
#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e+5 + 5;
const int maxm = 15e+4 + 5;
const int maxl = 1e+6 + 5;

int bel[maxl];

struct edge {
int to, nxt;
}e[maxm << 1];
struct question {
int typ, id, l, r, y;
inline bool operator<(const question &rhs) const {
return (bel[l] == bel[rhs.l]) ? r < rhs.r : bel[l] < bel[rhs.l];
}
}qst[maxn];
int n, m, q, lnk[maxn], ptr;
int dfn[maxn], low[maxn], cnt, seq[maxn], val[maxn], fa[maxn];
int lrs[maxn], vis[maxn], cnt2, w[maxn], oseq[maxn];

namespace MoAlg {
static const int blo = 505, N = 1e+6;
int ans[maxn], lb[maxl / blo + 5], rb[maxl / blo + 5];
int cnt[maxl], odd[maxl / blo + 5], even[maxl / blo + 5];
void build() {
lb[0] = rb[0] = 0;
bel[0] = 1;
int idx;
for (idx = 1; idx * blo < N; idx++) {
lb[idx] = rb[idx - 1] + 1; rb[idx] = lb[idx] + blo - 1;
for (int j = lb[idx]; j <= rb[idx]; ++j)
bel[j] = idx;
}
lb[idx] = rb[idx - 1] + 1; rb[idx] = N;
for (int j = lb[idx]; j <= rb[idx]; ++j)
bel[j] = idx;
}
inline void add(int x) {
if (!cnt[x]) {
odd[bel[x]]++;
} else if (cnt[x] & 1) {
odd[bel[x]]--, even[bel[x]]++;
} else {
even[bel[x]]--; odd[bel[x]]++;
}
cnt[x]++;
}
inline void del(int x) {
if (cnt[x] == 1) {
odd[bel[x]]--;
} else if (cnt[x] & 1) {
odd[bel[x]]--; even[bel[x]]++;
} else {
even[bel[x]]--; odd[bel[x]]++;
}
cnt[x]--;
}
inline int query_even(int L, int R) {
int ret = 0;
if (bel[L] == bel[R]) {
for (int i = L; i <= R; ++i)
if (cnt[i] && !(cnt[i] & 1)) ret++;
return ret;
}
for (int i = L; i <= rb[bel[L]]; ++i) if (cnt[i] && !(cnt[i] & 1)) ret++;
for (int i = bel[L] + 1; i < bel[R]; ++i) ret += even[i];
for (int i = lb[bel[R]]; i <= R; ++i) if (cnt[i] && !(cnt[i] & 1)) ret++;
return ret;
}
inline int query_odd(int L, int R) {
int ret = 0;
if (bel[L] == bel[R]) {
for (int i = L; i <= R; ++i) if (cnt[i] & 1) ret++;
return ret;
}
for (int i = L; i <= rb[bel[L]]; ++i) if (cnt[i] & 1) ret++;
for (int i = bel[L] + 1; i < bel[R]; ++i) ret += odd[i];
for (int i = lb[bel[R]]; i <= R; ++i) if (cnt[i] & 1) ret++;
return ret;
}
void solve() {
// build();
int L = 1, R = 0;
for (int i = 1; i <= q; ++i) {
while (L > qst[i].l) add(w[--L]);
while (R < qst[i].r) add(w[++R]);
while (L < qst[i].l) del(w[L++]);
while (R > qst[i].r) del(w[R--]);
ans[qst[i].id] = (!qst[i].typ) ? query_even(1, qst[i].y) : query_odd(1, qst[i].y);
}
for (int i = 1; i <= q; ++i)
printf("%d\n", ans[i]);
}
}

inline void add(int bgn, int end) {
e[++ptr] = (edge){end, lnk[bgn]};
lnk[bgn] = ptr;
}
inline int rd() {
register int x = 0, c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return x;
}
void tarjan(int x, int f) {
fa[x] = f;
dfn[x] = low[x] = ++cnt;
for (int p = lnk[x]; p; p = e[p].nxt) {
int y = e[p].to;
if (y == f) continue;
if (dfn[y]) {
if (dfn[y] < dfn[x]) low[x] = min(low[x], dfn[y]);
continue;
}
tarjan(y, x);
low[x] = min(low[x], low[y]);
if (low[y] < dfn[x]) lrs[x] = y;
}
}
void dfs(int x) {
vis[x] = 1;
seq[x] = ++cnt2; w[cnt2] = val[x];
for (int p = lnk[x]; p; p = e[p].nxt) {
int y = e[p].to;
if (vis[y] || y == lrs[x]) continue;
dfs(y);
}
oseq[x] = cnt2;
if (lrs[x]) dfs(lrs[x]);
}

int main() {
n = rd(); m = rd();
for (int i = 1; i <= n; ++i)
val[i] = rd();
int u, v;
for (int i = 1; i <= m; ++i) {
u = rd(); v = rd();
add(u, v); add(v, u);
}
tarjan(1, 0);
dfs(1);
q = rd();
for (int i = 1; i <= q; ++i) {
qst[i].typ = rd(); u = rd(); qst[i].y = rd();
qst[i].id = i; qst[i].l = seq[u]; qst[i].r = oseq[u];
}
MoAlg::build();
sort(qst + 1, qst + 1 + q);
MoAlg::solve();
return 0;
}

瞟了几眼设计模式后越来越厌恶这样混乱的代码, 全局乱开, 层次混乱, 大量重复代码, 变量名不清晰. 不过转念一想, 这是做算法题又不是开发应用, 和陈锋说的一样.