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 | #include <bits/stdc++.h>
#define MAXN ((int) 1e5)
#define MAXM ((int) 1e5)
#define MAXA ((int) 1e5)
using namespace std;
int n, m, A[MAXN + 10], ans[MAXM + 10];
vector<int> e[MAXN + 10], v[MAXN + 10];
int clk, dfn[MAXN + 10], low[MAXN + 10];
stack<int> stk;
bool inS[MAXN + 10];
int bCnt, bel[MAXN + 10];
vector<int> nums[MAXN + 10];
vector<int> E[MAXN + 10], V[MAXN + 10];
int CLK, ORD[MAXN + 10], DL[MAXN + 10], DR[MAXN + 10], SZ[MAXN + 10], HEAVY[MAXN + 10];
// 每次添加或删除一个数,求众数的出现次数
struct Mode {
int f[MAXA + 10], g[MAXN + 10], a;
void clear() {
for (int i = 1; i <= n; i++) f[A[i]] = 0;
for (int i = 1; i <= n; i++) g[i] = 0;
a = 0;
}
void add(int x) {
if (f[x]) g[f[x]]--;
f[x]++;
g[f[x]]++;
a = max(a, f[x]);
}
void del(int x) {
g[f[x]]--;
f[x]--;
if (f[x]) g[f[x]]++;
a = g[a] > 0 ? a : a - 1;
}
} M1, M2;
void tarjan(int sn, int from) {
low[sn] = dfn[sn] = ++clk;
stk.push(sn); inS[sn] = true;
for (int i = 0; i < e[sn].size(); i++) {
int fn = e[sn][i], val = v[sn][i];
if (val == from) continue;
if (!dfn[fn]) {
tarjan(fn, val);
low[sn] = min(low[sn], low[fn]);
} else if (inS[fn]) {
low[sn] = min(low[sn], dfn[fn]);
}
}
if (dfn[sn] == low[sn]) {
bCnt++;
while (stk.top() != sn) {
bel[stk.top()] = bCnt;
inS[stk.top()] = false; stk.pop();
}
bel[sn] = bCnt;
inS[sn] = false; stk.pop();
}
}
void DFS(int sn, int fa) {
DL[sn] = ++CLK; ORD[CLK] = sn;
SZ[sn] = nums[sn].size(); HEAVY[sn] = 0;
for (int fn : E[sn]) if (fn != fa) {
DFS(fn, sn);
SZ[sn] += SZ[fn];
if (SZ[HEAVY[sn]] < SZ[fn]) HEAVY[sn] = fn;
}
DR[sn] = CLK;
}
void DSU(int sn, bool keep, int from, int ALL) {
// 先遍历轻子树,不保留影响
for (int i = 0; i < E[sn].size(); i++) {
int fn = E[sn][i], val = V[sn][i];
if (val == from || fn == HEAVY[sn]) continue;
DSU(fn, false, val, ALL);
}
// 再遍历重子树,保留影响
for (int i = 0; i < E[sn].size(); i++) {
int fn = E[sn][i], val = V[sn][i];
if (fn == HEAVY[sn]) DSU(fn, true, val, ALL);
}
// 添加轻子树的影响
for (int i = 0; i < E[sn].size(); i++) {
int fn = E[sn][i], val = V[sn][i];
if (val == from || fn == HEAVY[sn]) continue;
for (int j = DL[fn]; j <= DR[fn]; j++) for (int x : nums[ORD[j]]) M1.add(x), M2.del(x);
}
// 添加节点本身的影响
for (int x : nums[sn]) M1.add(x), M2.del(x);
// 此时节点 sn 的答案就可以求了
if (from) ans[from] = M1.a + M2.a - ALL;
if (keep) return;
// 回撤子树 sn 的影响
for (int j = DL[sn]; j <= DR[sn]; j++) for (int x : nums[ORD[j]]) M1.del(x), M2.add(x);
}
void solve() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &A[i]);
for (int i = 1; i <= n; i++) e[i].clear(), v[i].clear();
for (int i = 1; i <= m; i++) {
int x, y; scanf("%d%d", &x, &y);
e[x].push_back(y); v[x].push_back(i);
e[y].push_back(x); v[y].push_back(i);
}
clk = 0; bCnt = 0;
memset(dfn, 0, sizeof(int) * (n + 3));
for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, 0);
for (int i = 1; i <= n; i++) nums[i].clear();
for (int i = 1; i <= n; i++) nums[bel[i]].push_back(A[i]);
for (int i = 1; i <= n; i++) E[i].clear(), V[i].clear();
for (int sn = 1; sn <= n; sn++) for (int i = 0; i < e[sn].size(); i++) {
int fn = e[sn][i], val = v[sn][i];
if (bel[sn] == bel[fn]) continue;
E[bel[sn]].push_back(bel[fn]); V[bel[sn]].push_back(val);
}
CLK = 0;
memset(DL, 0, sizeof(int) * (n + 3));
memset(ans, 0, sizeof(int) * (m + 3));
for (int i = 1; i <= n; i++) if (!DL[i]) {
DFS(i, 0);
for (int j = DL[i]; j <= DR[i]; j++) for (int x : nums[ORD[j]]) M2.add(x);
ans[0] += M2.a;
DSU(i, false, 0, M2.a);
for (int j = DL[i]; j <= DR[i]; j++) for (int x : nums[ORD[j]]) M2.del(x);
}
for (int i = 1; i <= m; i++) printf("%d%c", ans[i] + ans[0], "\n "[i < m]);
M1.clear(); M2.clear();
}
int main() {
int tcase; scanf("%d", &tcase);
while (tcase--) solve();
return 0;
}
|