Skip to content

Commit 7c52a35

Browse files
committed
Two implementations for JOI factories
1 parent 66d2ab0 commit 7c52a35

File tree

6 files changed

+204
-0
lines changed

6 files changed

+204
-0
lines changed

.vscode/launch.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "g++.exe - Build and debug active file",
9+
"type": "cppdbg",
10+
"request": "launch",
11+
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
12+
"args": [],
13+
"stopAtEntry": false,
14+
"cwd": "C:\\MinGW\\bin",
15+
"environment": [],
16+
"externalConsole": false,
17+
"MIMode": "gdb",
18+
"miDebuggerPath": "C:\\MinGW\\bin\\gdb.exe",
19+
"setupCommands": [
20+
{
21+
"description": "Enable pretty-printing for gdb",
22+
"text": "-enable-pretty-printing",
23+
"ignoreFailures": true
24+
}
25+
],
26+
"preLaunchTask": "C/C++: g++.exe build active file"
27+
}
28+
]
29+
}

.vscode/settings.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"files.associations": {
3+
"string": "cpp",
4+
"chrono": "cpp",
5+
"random": "cpp",
6+
"limits": "cpp",
7+
"valarray": "cpp"
8+
}
9+
}

.vscode/tasks.json

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"tasks": [
3+
{
4+
"type": "cppbuild",
5+
"label": "C/C++: g++.exe build active file",
6+
"command": "C:\\MinGW\\bin\\g++.exe",
7+
"args": [
8+
"-g",
9+
"${file}",
10+
"-o",
11+
"${fileDirname}\\${fileBasenameNoExtension}.exe"
12+
],
13+
"options": {
14+
"cwd": "C:\\MinGW\\bin"
15+
},
16+
"problemMatcher": [
17+
"$gcc"
18+
],
19+
"group": {
20+
"kind": "build",
21+
"isDefault": true
22+
},
23+
"detail": "Task generated by Debugger."
24+
}
25+
],
26+
"version": "2.0.0"
27+
}

Balkan/.vscode/settings.json

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"files.associations": {
3+
"*.tcc": "cpp",
4+
"array": "cpp",
5+
"memory": "cpp",
6+
"future": "cpp",
7+
"istream": "cpp",
8+
"functional": "cpp",
9+
"tuple": "cpp",
10+
"utility": "cpp",
11+
"variant": "cpp"
12+
}
13+
}

JOI/JOI 14-factories/virtual tree.cpp

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
JOI 2014 Factories
3+
- If there were very few queries, then we can do a simple tree DP to find min(dist to X + dist to Y) from each node
4+
- Notice however that the only "important" nodes we need to check are on the virtual tree from (X union Y)
5+
- We can thus construct the virtual tree for each query and then do tree DP on it to answer the query
6+
- Complexity: O(V log N) where V = sum(S + T)
7+
*/
8+
9+
#include "factories.h"
10+
11+
#include <bits/stdc++.h>
12+
typedef long long ll;
13+
using namespace std;
14+
15+
const ll INF = 1e18;
16+
17+
vector<pair<int, ll>> graph[500000], vtree[500000];
18+
int tin[500000], tout[500000], timer = 0, anc[500000][19];
19+
ll to_anc[500000][19], to_X[500000], to_Y[500000];
20+
21+
void lca_dfs(int node = 0, int parent = -1) {
22+
tin[node] = timer++;
23+
for (int i = 1; i < 19; i++) {
24+
anc[node][i] = anc[anc[node][i - 1]][i - 1];
25+
to_anc[node][i] = to_anc[node][i - 1] + to_anc[anc[node][i - 1]][i - 1];
26+
}
27+
for (pair<int, ll> i : graph[node]) if (i.first != parent) {
28+
anc[i.first][0] = node;
29+
to_anc[i.first][0] = i.second;
30+
lca_dfs(i.first, node);
31+
}
32+
tout[node] = timer++;
33+
}
34+
35+
inline bool is_ancestor(int u, int v) { return (tin[u] <= tin[v] && tout[u] >= tout[v]); }
36+
37+
int lca(int u, int v) {
38+
if (is_ancestor(u, v)) return u;
39+
for (int i = 18; ~i; i--) if (!is_ancestor(anc[u][i], v)) u = anc[u][i];
40+
return anc[u][0];
41+
}
42+
43+
ll dist(int u, int v) {
44+
ll ans = 0;
45+
for (int i = 18; ~i; i--) if (!is_ancestor(anc[u][i], v)) {
46+
ans += to_anc[u][i];
47+
u = anc[u][i];
48+
}
49+
if (!is_ancestor(u, v)) ans += to_anc[u][0];
50+
for (int i = 18; ~i; i--) if (!is_ancestor(anc[v][i], u)) {
51+
ans += to_anc[v][i];
52+
v = anc[v][i];
53+
}
54+
if (!is_ancestor(v, u)) ans += to_anc[v][0];
55+
return ans;
56+
}
57+
58+
void Init(int N, int A[], int B[], int D[]) {
59+
for (int i = 0; i < N - 1; i++) {
60+
graph[A[i]].push_back({B[i], D[i]});
61+
graph[B[i]].push_back({A[i], D[i]});
62+
}
63+
lca_dfs();
64+
memset(to_X, 0x3f, sizeof to_X); memset(to_Y, 0x3f, sizeof to_Y);
65+
}
66+
67+
bool cmp(int u, int v) { return tin[u] < tin[v]; }
68+
69+
ll ans;
70+
71+
void dfs1(int node, int parent = 0) {
72+
for (pair<int, ll> i : vtree[node]) if (i.first != parent) {
73+
dfs1(i.first, node);
74+
to_X[node] = min(to_X[node], to_X[i.first] + i.second);
75+
to_Y[node] = min(to_Y[node], to_Y[i.first] + i.second);
76+
}
77+
}
78+
79+
void dfs2(int node, int parent = 0, ll par_to_X = INF, ll par_to_Y = INF) {
80+
to_X[node] = min(to_X[node], par_to_X);
81+
to_Y[node] = min(to_Y[node], par_to_Y);
82+
ans = min(ans, to_X[node] + to_Y[node]);
83+
for (pair<int, ll> i : vtree[node]) if (i.first != parent) {
84+
ll nxt_par_to_X = i.second + min(par_to_X, to_X[node]);
85+
ll nxt_par_to_Y = i.second + min(par_to_Y, to_Y[node]);
86+
dfs2(i.first, node, nxt_par_to_X, nxt_par_to_Y);
87+
}
88+
}
89+
90+
ll Query(int S, int X[], int T, int Y[]) {
91+
vector<int> nodes;
92+
for (int i = 0; i < S; i++) {
93+
to_X[X[i]] = 0;
94+
nodes.push_back(X[i]);
95+
}
96+
for (int i = 0; i < T; i++) {
97+
to_Y[Y[i]] = 0;
98+
nodes.push_back(Y[i]);
99+
}
100+
sort(nodes.begin(), nodes.end(), cmp);
101+
for (int i = 1; i < S + T; i++) nodes.push_back(lca(nodes[i - 1], nodes[i]));
102+
sort(nodes.begin(), nodes.end(), cmp);
103+
nodes.erase(unique(nodes.begin(), nodes.end()), nodes.end());
104+
vector<int> stck;
105+
for (int i : nodes) {
106+
while (stck.size() > 1 && !is_ancestor(stck.back(), i)) {
107+
int u = stck[stck.size() - 2], v = stck.back();
108+
vtree[u].push_back({v, dist(u, v)});
109+
stck.pop_back();
110+
}
111+
stck.push_back(i);
112+
}
113+
while (stck.size() > 1) {
114+
int u = stck[stck.size() - 2], v = stck.back();
115+
vtree[u].push_back({v, dist(u, v)});
116+
stck.pop_back();
117+
}
118+
ans = LLONG_MAX;
119+
dfs1(stck[0]);
120+
dfs2(stck[0]);
121+
for (int i : nodes) {
122+
to_X[i] = to_Y[i] = INF;
123+
vtree[i].clear();
124+
}
125+
return ans;
126+
}

0 commit comments

Comments
 (0)