-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProblem_2846_minOperationsQueries.cc
167 lines (142 loc) · 3.8 KB
/
Problem_2846_minOperationsQueries.cc
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
158
159
160
161
162
163
164
165
166
167
#include <vector>
using namespace std;
// TODO: fix it. run out of time.
class Solution
{
public:
static const int MAXN = 10001;
static const int MAXM = 20001;
static const int MAXW = 26;
// 链式前向星建图
vector<int> headEdge = vector<int>(MAXN);
vector<int> edgeNext = vector<int>(MAXN << 1);
vector<int> edgeTo = vector<int>(MAXN << 1);
vector<int> edgeValue = vector<int>(MAXN << 1);
int tcnt;
// weightCnt[i][w] : 从头节点到i的路径中,权值为w的边有几条
vector<vector<int>> weightCnt = vector<vector<int>>(MAXN, vector<int>(MAXW + 1));
// 以下所有的结构都是为了tarjan算法做准备
vector<int> headQuery = vector<int>(MAXN);
vector<int> queryNext = vector<int>(MAXM << 1);
vector<int> queryTo = vector<int>(MAXM << 1);
vector<int> queryIndex = vector<int>(MAXM << 1);
int qcnt;
vector<bool> visited = vector<bool>(MAXN);
vector<int> father = vector<int>(MAXN);
vector<int> lca = vector<int>(MAXM);
vector<int> minOperationsQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries)
{
build(n);
for (auto& edge : edges)
{
addEdge(edge[0], edge[1], edge[2]);
addEdge(edge[1], edge[0], edge[2]);
}
// 从头节点到每个节点的边权值词频统计
dfs(0, 0, -1);
int m = queries.size();
for (int i = 0; i < m; i++)
{
addQuery(queries[i][0], queries[i][1], i);
addQuery(queries[i][1], queries[i][0], i);
}
// 得到每个查询的最低公共祖先
tarjan(0, -1);
vector<int> ans(m);
for (int i = 0, a, b, c; i < m; i++)
{
a = queries[i][0];
b = queries[i][1];
c = lca[i];
int allCnt = 0; // 从a到b的路,所有权值的边一共多少条
int maxCnt = 0; // 从a到b的路,权值重复最多的次数
for (int w = 1, wcnt; w <= MAXW; w++)
{ // 所有权值枚举一遍
wcnt = weightCnt[a][w] + weightCnt[b][w] - 2 * weightCnt[c][w];
maxCnt = std::max(maxCnt, wcnt);
allCnt += wcnt;
}
ans[i] = allCnt - maxCnt;
}
return ans;
}
void build(int n)
{
tcnt = qcnt = 1;
std::fill(headEdge.begin(), headEdge.begin() + n, 0);
std::fill(headQuery.begin(), headQuery.begin() + n, 0);
std::fill(visited.begin(), visited.begin() + n, false);
for (int i = 0; i < n; i++)
{
father[i] = i;
}
}
void addEdge(int u, int v, int w)
{
edgeNext[tcnt] = headEdge[u];
edgeTo[tcnt] = v;
edgeValue[tcnt] = w;
headEdge[u] = tcnt++;
}
// 当前来到u节点,父亲节点f,从f到u权重为w
// 统计从头节点到u节点,每种权值的边有多少条
// 信息存放在weightCnt[u][1..26]里
void dfs(int u, int w, int f)
{
if (u == 0)
{
std::fill(weightCnt[u].begin(), weightCnt[u].end(), 0);
}
else
{
for (int i = 1; i <= MAXW; i++)
{
weightCnt[u][i] = weightCnt[f][i];
}
weightCnt[u][w]++;
}
for (int e = headEdge[u]; e != 0; e = edgeNext[e])
{
if (edgeTo[e] != f)
{
dfs(edgeTo[e], edgeValue[e], u);
}
}
}
void addQuery(int u, int v, int i)
{
queryNext[qcnt] = headQuery[u];
queryTo[qcnt] = v;
queryIndex[qcnt] = i;
headQuery[u] = qcnt++;
}
// tarjan算法批量查询两点的最低公共祖先
void tarjan(int u, int f)
{
visited[u] = true;
for (int e = headEdge[u]; e != 0; e = edgeNext[e])
{
if (edgeTo[e] != f)
{
tarjan(edgeTo[e], u);
}
}
for (int e = headQuery[u], v; e != 0; e = queryNext[e])
{
v = queryTo[e];
if (visited[v])
{
lca[queryIndex[e]] = find(v);
}
}
father[u] = f;
}
int find(int i)
{
if (i != father[i])
{
father[i] = find(father[i]);
}
return father[i];
}
};