# |
Submission time |
Handle |
Problem |
Language |
Result |
Execution time |
Memory |
941999 |
2024-03-10T01:46:16 Z |
riariti |
Toll (APIO13_toll) |
C++17 |
|
2308 ms |
24896 KB |
#line 1 "Toll.cpp"
#include <bits/stdc++.h>
#line 2 "/Users/jeff/Documents/git_repos/competitive/cplib/environment/dbg.hpp"
#if defined(local)
#include <debug>
#else
#define dbg(...)
#endif
#line 4 "Toll.cpp"
#define int std::int64_t
using namespace std;
typedef long long lint;
typedef pair<int, int> pi;
struct disj {
int pa[100005];
void init(int n) {
for (int i = 1; i <= n; i++) {
pa[i] = i;
}
}
int find(int x) { return pa[x] = (pa[x] == x ? x : find(pa[x])); }
bool uni(int p, int q) {
p = find(p);
q = find(q);
if (p == q)
return 0;
pa[q] = p;
return 1;
}
} disj;
struct edg {
int s, e, x;
bool operator<(const edg &e) const { return x < e.x; }
} a[300005];
int n, m, k, s[22], e[22], c[100005];
vector<int> gph[100005];
vector<edg> resi;
int p, comp[100005];
lint csize[25];
int par[25], pae[25], chk[25], dep[25];
lint sz[25];
vector<pi> gph2[25];
void dfs2(int x, int p) {
sz[x] = csize[x];
for (auto &i : gph2[x]) {
if (i.first == p)
continue;
chk[i.first] = i.second;
dep[i.first] = dep[x] + 1;
pae[i.first] = 1e9;
par[i.first] = x;
dfs2(i.first, x);
sz[x] += sz[i.first];
}
}
lint solve(int b) {
dbg("solve");
for (int i = 1; i <= p; i++) {
gph2[i].clear();
}
disj.init(p);
for (int i = 0; i < k; i++) {
if ((b >> i) & 1) {
if (!disj.uni(s[i], e[i])) {
return -1;
}
dbg(s[i], e[i]);
gph2[s[i]].push_back({e[i], 1});
gph2[e[i]].push_back({s[i], 1});
}
}
vector<edg> resi2;
for (auto &i : resi) {
if (disj.uni(i.s, i.e)) {
dbg(i.s, i.e);
gph2[i.s].push_back({i.e, 0});
gph2[i.e].push_back({i.s, 0});
} else {
dbg("resi2", i.s, i.e);
resi2.push_back(i);
}
}
dfs2(1, -1);
for (int i = 1; i <= n; i++) {
dbg(i);
dbg(par[i]);
dbg(chk[i]);
dbg(dep[i]);
dbg(sz[i]);
dbg(csize[i]);
dbg(pae[i]);
}
for (auto &i : resi2) {
if (dep[i.s] < dep[i.e])
swap(i.s, i.e);
while (dep[i.s] > dep[i.e]) {
pae[i.s] = min(pae[i.s], i.x);
i.s = par[i.s];
}
while (i.s != i.e) {
pae[i.s] = min(pae[i.s], i.x);
pae[i.e] = min(pae[i.e], i.x);
i.s = par[i.s];
i.e = par[i.e];
}
}
lint ret = 0;
for (int i = 2; i <= p; i++) {
if (chk[i])
ret += sz[i] * pae[i];
}
return ret;
}
void dfs(int x, int p) {
if (comp[x])
return;
csize[p] += c[x];
comp[x] = p;
for (auto &i : gph[x]) {
dfs(i, p);
}
}
void compress() {
disj.init(n);
for (int i = 0; i < k; i++) {
dbg(s[i], e[i]);
disj.uni(s[i], e[i]);
}
for (int i = 0; i < n - 1; i++) {
if (disj.uni(a[i].s, a[i].e)) {
dbg(a[i].e, a[i].s);
gph[a[i].e].push_back(a[i].s);
gph[a[i].s].push_back(a[i].e);
} else {
dbg("resi", a[i].e, a[i].s);
resi.push_back(a[i]);
}
}
for (int i = 1; i <= n; i++) {
if (!comp[i]) {
dfs(i, ++p);
}
}
for (int i = 1; i <= n; i++) {
dbg(comp[i]);
}
for (auto &i : resi) {
i.s = comp[i.s];
i.e = comp[i.e];
dbg(i.s, i.e);
}
for (int i = 0; i < k; i++) {
s[i] = comp[s[i]];
e[i] = comp[e[i]];
dbg(s[i], e[i]);
}
}
void sol(int N, int M, int K, std::vector<std::array<int, 3>> &abc,
std::vector<std::array<int, 3>> &xy, std::vector<int> &C) {
n = N;
m = M;
k = K;
dbg(n, m, k);
for (int i = 0; i < m; i++) {
a[i].s = abc[i][0];
a[i].e = abc[i][1];
a[i].x = abc[i][2];
dbg(a[i].s, a[i].e, a[i].x);
}
for (int i = 0; i < k; i++) {
s[i] = xy[i][0];
e[i] = xy[i][1];
dbg(s[i], e[i]);
}
for (int i = 1; i <= n; i++) {
c[i] = C[i - 1];
}
sort(a, a + m);
disj.init(n);
dbg("here");
vector<edg> tree;
dbg("here");
int cnt = 0;
for (int i = 0; i < m; i++) {
dbg("hi");
if (disj.uni(a[i].s, a[i].e)) {
dbg("hi", a[i].s, a[i].e);
cnt++;
tree.push_back(a[i]);
}
}
dbg("here", cnt);
for (int i = 0; i < n - 1; i++) {
a[i] = tree[i];
}
dbg("here");
compress();
lint ret = 0;
for (int i = 1; i < (1 << k); i++) {
ret = max(ret, solve(i));
}
dbg(ret);
dbg("-----------------------");
}
std::int32_t main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
// https://dmoj.ca/problem/apio13p2/editorial
// getting used to style :()
// got until observation 3 without any doubts
// // kruskal-ish way
// std::sort(abc.begin(), abc.end(),
// [&](auto x, auto y) { return x[2] < y[2]; });
// // K <= 20 => 2^K = 1048576
// // bitmasks which of them we should take then put max value so that they
// are
// // still included in minimum spanning tree
// const auto k = 1 << K;
// // store the max weight so that edge is contained only compared to the
// // other constant it possibly does not change what about cases where it
// is
// // compared to other non-constants
// // kruskal on original edges
// connect 2 components (see if there were additional edges)
// atrribute that you can replace the edge with the additional edges (now
// are a group of edges)
// choose any 1 from the group
// weight = to original weight
// nah
constexpr int INF = 1E9 + 9;
int N, M, K;
std::cin >> N >> M >> K;
dbg(N, M, K);
std::vector<std::array<int, 3>> abc(M);
for (int i = 0; i < M; i++) {
auto &[a, b, c] = abc[i];
std::cin >> a >> b >> c;
// a--;
// b--;
}
std::vector<std::array<int, 3>> xy(K);
for (int i = 0; i < K; i++) {
auto &[x, y, w] = xy[i];
std::cin >> x >> y;
// w = INF;
// x--;
// y--;
}
std::vector<int> c(N);
for (int i = 0; i < N; i++) {
std::cin >> c[i];
}
// sol(N, M, K, abc, xy, c);
for (int i = 0; i < M; i++) {
auto &[a, b, c] = abc[i];
a--;
b--;
}
for (int i = 0; i < K; i++) {
auto &[x, y, w] = xy[i];
w = INF;
x--;
y--;
}
dbg(abc);
dbg(xy);
dbg(c);
struct DSU {
int n;
std::vector<int> f;
std::vector<int> siz;
DSU() {}
explicit DSU(int _n) : n(_n), f(_n), siz(_n) {
std::iota(f.begin(), f.end(), 0);
siz.assign(n, -1);
}
int find(int x) {
while (x != f[x]) {
x = f[x] = f[f[x]];
}
return x;
}
bool same(int x, int y) { return find(x) == find(y); }
bool merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y) {
return false;
}
siz[x] += siz[y];
f[y] = x;
return true;
}
int size(int x) { return siz[find(x)]; }
};
std::vector<std::array<int, 3>> mst;
auto kruskal = [&]() -> void {
// make mst
std::sort(abc.begin(), abc.end(),
[](const auto &x, const auto &y) { return x[2] < y[2]; });
dbg(abc);
// kruskal
DSU dsu(N);
for (int i = 0; i < M; i++) {
auto [a, b, c] = abc[i];
if (dsu.merge(a, b)) {
mst.push_back({a, b, c});
}
}
dbg(mst);
};
kruskal();
// dont need the bad ori edges / extra useless weight
abc = std::move(mst);
mst.clear();
dbg(abc);
// M = N - 1
M = abc.size();
dbg(M);
// compress into at max k components (since that is what the questin says)
// => local (inside) and global path for each component
// local does not change, at max k vertexs, one from each from current to
// outside component (at max k components)
// value is from root until the local root (root of the compoent ) is called
// global path else inside it is called local path (computation to all can
// be done via O(n) + O(1) of lca or O(nk) with simple dfs or O(n) with dfs
// + rerooting)
// local cost does not depend on query but global does => lcoal cost precomp
// + global cost recalc with dfs O(k) vertexs only can be done in O(nk + 2^k
// * k) or O(n + 2^k * k) both passable
std::vector<std::vector<int>> adj(N);
// components mapping, number of people
std::vector<int> cmp(N, -1), np(N);
int C = -1;
// not part of k vertexs
std::vector<std::array<int, 3>> npk;
// compression to differniate the k edges and original edges and then group
// them up into components for quicker query since local does not change
// only global does, and so we have to compress as mentioned above
auto compress = [&]() -> void {
DSU dsu(N);
// choose the vertexs which get affected by the k new nodes
// / the k edges themselves
for (int i = 0; i < K; i++) {
auto [x, y, w] = xy[i];
dbg(x, y, w);
if (dsu.merge(x, y)) {
dbg(x, y);
}
}
// go through the mst to see which paths between vertexs get affected
for (int i = 0; i < M; i++) {
auto [a, b, c] = abc[i];
if (dsu.merge(a, b)) {
dbg(a, b);
// ok so not affected => take
// dont put the graph edge of x y
// since we want to find the compoents where it is seperated
adj[a].push_back(b);
adj[b].push_back(a);
} else {
// affeceted => cant take => but still compress
// to see where the nodes end up at i.e which component
// part of the components centered by the above k vertexs
// will be used especially since we are not going to take all of
// the K all the K edges, sometimes only a subset
npk.push_back({a, b, c});
}
}
dbg(npk);
// fill in components i.e what component will vertex a, b and so on
// belong to and how many people are from there
dbg(cmp);
for (int i = 0, p = 0; i < N; i++) {
if (cmp[i] != -1) {
continue;
}
auto dfs = [&](auto &&self, int x) {
// baiscally like vis
if (cmp[x] != -1) {
return;
}
dbg(np[p], c[x]);
np[p] += c[x];
cmp[x] = p;
for (auto y : adj[x]) {
self(self, y);
}
};
dfs(dfs, i);
p++;
C = p;
}
dbg(cmp, C);
dbg(np);
// convert them to components
for (int i = 0; i < npk.size(); i++) {
auto &[a, b, c] = npk[i];
a = cmp[a];
b = cmp[b];
dbg(a, b);
}
// convert the k edges into which compoentes they belng to
for (int i = 0; i < K; i++) {
auto &[x, y, w] = xy[i];
x = cmp[x];
y = cmp[y];
dbg(x, y);
}
};
compress();
auto sol = [&](const std::vector<int> &idx) -> std::int64_t {
dbg(idx);
DSU dsu(C);
std::vector<std::vector<std::pair<int, int>>> gdj(C);
for (auto i : idx) {
auto [x, y, w] = xy[i];
// it should not be a cycle
if (!dsu.merge(x, y)) {
return -1;
}
dbg(x, y);
// 1 weight and 0 for the non (chosen) k edges and original edges
// for check function since we only can add values if they pass
// through this edge
gdj[x].push_back({y, 1});
gdj[y].push_back({x, 1});
}
// dbg(gdj);
// again similar with compression, but now only with the non chosen k
// edges
std::vector<std::array<int, 3>> npl;
// make sure onyl from the original non (all) k edges
for (auto [a, b, c] : npk) {
dbg(a, b, c);
if (dsu.merge(a, b)) {
dbg("here", a, b);
// 0 for the non profit edges
gdj[a].push_back({b, 0});
gdj[b].push_back({a, 0});
} else {
npl.push_back({a, b, c});
}
}
dbg(npl);
std::vector<int> par(C, -1), chk(C), dep(C), siz(C);
// np = weight of edges that will get paid from
// pae = all k's edges or nah (will be used for cost calc or nah)
std::vector<int> pae(C);
// std::vector<int> np(N), pae(N);
// np alreadyinitialized
// O(K) vertexs
auto dfs = [&](auto &&self, int x) -> void {
// siz is number fo people
siz[x] = np[x];
for (auto [y, w] : gdj[x]) {
if (y == par[x]) {
continue;
}
par[y] = x;
chk[y] = w;
dep[y] = dep[x] + 1;
pae[y] = INF;
self(self, y);
siz[x] += siz[y];
}
};
dfs(dfs, 0);
dbg(par);
dbg(chk);
dbg(dep);
dbg(siz);
dbg(np);
dbg(pae);
for (auto [a, b, c] : npl) {
// mins here are to check if all of them are have weight
// the min weight here is the dependent on the k edges
// so the win weight / cost of the k edges here are the 0's and 1's
// basically checking if it will benefit him or nah
// if it passess through only the k edgees then only will the val
// will be 1 else 0 i.e the person wont get any money
// and it si possible since siz is basicaly like a prefix sum
// so if we add it onyl where it passes through the kedges => it is
// still answer since it tells how many people pass through it
// confirm
// lca path checking basically
if (dep[a] < dep[b]) {
std::swap(a, b);
}
// equalize depth
while (dep[a] > dep[b]) {
pae[a] = std::min(pae[a], c);
a = par[a];
}
// lca
while (a != b) {
pae[a] = std::min(pae[a], c);
pae[b] = std::min(pae[b], c);
a = par[a];
b = par[b];
}
}
int ans = 0;
for (int i = 1; i < C; i++) {
if (!chk[i]) {
continue;
}
ans += siz[i] * pae[i];
}
return ans;
};
const auto bit_set = [](int v, int k) -> bool { return v & (1 << k); };
std::int64_t ans = 0;
for (int k = 0; k < (1 << K); k++) {
std::vector<int> idx;
for (int i = 0; i < K; i++) {
if (!bit_set(k, i)) {
continue;
}
idx.push_back(i);
}
ans = std::max(ans, sol(idx));
}
std::cout << ans << "\n";
#undef int
return 0;
}
Compilation message
Toll.cpp: In lambda function:
Toll.cpp:460:27: warning: comparison of integer expressions of different signedness: 'int64_t' {aka 'long int'} and 'std::vector<std::array<long int, 3> >::size_type' {aka 'long unsigned int'} [-Wsign-compare]
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
1 ms |
4444 KB |
Output is correct |
2 |
Correct |
1 ms |
4444 KB |
Output is correct |
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
1 ms |
4444 KB |
Output is correct |
2 |
Correct |
1 ms |
4444 KB |
Output is correct |
3 |
Correct |
2 ms |
4444 KB |
Output is correct |
4 |
Correct |
2 ms |
4444 KB |
Output is correct |
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
1 ms |
4444 KB |
Output is correct |
2 |
Correct |
1 ms |
4444 KB |
Output is correct |
3 |
Correct |
2 ms |
4444 KB |
Output is correct |
4 |
Correct |
2 ms |
4444 KB |
Output is correct |
5 |
Correct |
3 ms |
4700 KB |
Output is correct |
6 |
Correct |
3 ms |
4696 KB |
Output is correct |
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
1 ms |
4444 KB |
Output is correct |
2 |
Correct |
1 ms |
4444 KB |
Output is correct |
3 |
Correct |
2 ms |
4444 KB |
Output is correct |
4 |
Correct |
2 ms |
4444 KB |
Output is correct |
5 |
Correct |
3 ms |
4700 KB |
Output is correct |
6 |
Correct |
3 ms |
4696 KB |
Output is correct |
7 |
Correct |
175 ms |
24656 KB |
Output is correct |
8 |
Correct |
180 ms |
23368 KB |
Output is correct |
9 |
Correct |
175 ms |
23496 KB |
Output is correct |
# |
Verdict |
Execution time |
Memory |
Grader output |
1 |
Correct |
1 ms |
4444 KB |
Output is correct |
2 |
Correct |
1 ms |
4444 KB |
Output is correct |
3 |
Correct |
2 ms |
4444 KB |
Output is correct |
4 |
Correct |
2 ms |
4444 KB |
Output is correct |
5 |
Correct |
3 ms |
4700 KB |
Output is correct |
6 |
Correct |
3 ms |
4696 KB |
Output is correct |
7 |
Correct |
175 ms |
24656 KB |
Output is correct |
8 |
Correct |
180 ms |
23368 KB |
Output is correct |
9 |
Correct |
175 ms |
23496 KB |
Output is correct |
10 |
Correct |
1881 ms |
23412 KB |
Output is correct |
11 |
Correct |
2308 ms |
24780 KB |
Output is correct |
12 |
Correct |
2307 ms |
24896 KB |
Output is correct |