結果
| 問題 |
No.1002 Twotone
|
| コンテスト | |
| ユーザー |
maspy
|
| 提出日時 | 2021-12-31 15:06:52 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
AC
|
| 実行時間 | 1,385 ms / 5,000 ms |
| コード長 | 12,306 bytes |
| コンパイル時間 | 2,823 ms |
| コンパイル使用メモリ | 235,968 KB |
| 最終ジャッジ日時 | 2025-01-27 08:08:26 |
|
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 33 |
ソースコード
#line 2 "/home/maspy/library/my_template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ll8 = __int128;
using ld = long double;
using pi = pair<ll, ll>;
using vi = vector<ll>;
using uint = unsigned int;
using ull = unsigned long long;
template <class T>
using vc = vector<T>;
template <class T>
using vvc = vector<vc<T>>;
template <class T>
using vvvc = vector<vvc<T>>;
template <class T>
using vvvvc = vector<vvvc<T>>;
template <class T>
using vvvvvc = vector<vvvvc<T>>;
template <class T>
using pq = priority_queue<T>;
template <class T>
using pqg = priority_queue<T, vector<T>, greater<T>>;
#define vec(type, name, ...) vector<type> name(__VA_ARGS__)
#define VEC(type, name, size) \
vector<type> name(size); \
IN(name)
#define vv(type, name, h, ...) \
vector<vector<type>> name(h, vector<type>(__VA_ARGS__))
#define VV(type, name, h, w) \
vector<vector<type>> name(h, vector<type>(w)); \
IN(name)
#define vvv(type, name, h, w, ...) \
vector<vector<vector<type>>> name( \
h, vector<vector<type>>(w, vector<type>(__VA_ARGS__)))
#define vvvv(type, name, a, b, c, ...) \
vector<vector<vector<vector<type>>>> name( \
a, vector<vector<vector<type>>>( \
b, vector<vector<type>>(c, vector<type>(__VA_ARGS__))))
#define FOR(i, n) for (ll i = 0; (i) < (ll)(n); ++(i))
#define FOR3(i, m, n) for (ll i = (m); (i) < (ll)(n); ++(i))
#define FOR_R(i, n) for (ll i = (ll)(n)-1; (i) >= 0; --(i))
#define FOR3_R(i, m, n) for (ll i = (ll)(n)-1; (i) >= (ll)(m); --(i))
#define FOR_subset(t, s) for (ll t = s; t >= 0; t = (t == 0 ? -1 : (t - 1) & s))
#define all(x) x.begin(), x.end()
#define len(x) ll(x.size())
#define elif else if
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
int popcnt(int x) { return __builtin_popcount(x); }
int popcnt(uint x) { return __builtin_popcount(x); }
int popcnt(ll x) { return __builtin_popcountll(x); }
int popcnt(ull x) { return __builtin_popcountll(x); }
// (0, 1, 2, 3, 4) -> (-1, 0, 1, 1, 2)
int topbit(int x) { return 31 - __builtin_clz(x); }
int topbit(uint x) { return 31 - __builtin_clz(x); }
int topbit(ll x) { return 63 - __builtin_clzll(x); }
int topbit(ull x) { return 63 - __builtin_clzll(x); }
// (0, 1, 2, 3, 4) -> (32 or 64, 0, 1, 0, 2)
int lowbit(int x) { return 31 - __builtin_clz(x); }
int lowbit(uint x) { return 31 - __builtin_clz(x); }
int lowbit(ll x) { return 63 - __builtin_clzll(x); }
int lowbit(ull x) { return 63 - __builtin_clzll(x); }
ll ceil(ll x, ll y) { return (x > 0 ? (x + y - 1) / y : x / y); }
ll floor(ll x, ll y) { return (x > 0 ? x / y : (x - y + 1) / y); }
pi divmod(ll x, ll y) {
ll q = floor(x, y);
return {q, x - q * y};
}
#define INT(...) \
int __VA_ARGS__; \
IN(__VA_ARGS__)
#define LL(...) \
ll __VA_ARGS__; \
IN(__VA_ARGS__)
#define STR(...) \
string __VA_ARGS__; \
IN(__VA_ARGS__)
#define CHR(...) \
char __VA_ARGS__; \
IN(__VA_ARGS__)
#define DBL(...) \
long double __VA_ARGS__; \
IN(__VA_ARGS__)
void scan(int &a) { cin >> a; }
void scan(long long &a) { cin >> a; }
void scan(char &a) { cin >> a; }
void scan(double &a) { cin >> a; }
void scan(long double &a) { cin >> a; }
void scan(string &a) { cin >> a; }
template <class T>
void scan(pair<T, T> &p) {
scan(p.first), scan(p.second);
}
template <class T>
void scan(tuple<T, T, T> &p) {
scan(get<0>(p)), scan(get<1>(p)), scan(get<2>(p));
}
template <class T>
void scan(tuple<T, T, T, T> &p) {
scan(get<0>(p)), scan(get<1>(p)), scan(get<2>(p)), scan(get<3>(p));
}
template <class T>
void scan(vector<T> &a) {
for (auto &i: a) scan(i);
}
template <class T>
void scan(T &a) {
cin >> a;
}
void IN() {}
template <class Head, class... Tail>
void IN(Head &head, Tail &... tail) {
scan(head);
IN(tail...);
}
vi s_to_vi(string S, char first_char = 'a') {
vi A(S.size());
FOR(i, S.size()) { A[i] = S[i] - first_char; }
return A;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &A) {
os << A.fi << " " << A.se;
return os;
}
template <typename T1, typename T2, typename T3>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3> &t) {
os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t);
return os;
}
template <typename T1, typename T2, typename T3, typename T4>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4> &t) {
os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " " << get<3>(t);
return os;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &A) {
for (size_t i = 0; i < A.size(); i++) {
if (i) os << " ";
os << A[i];
}
return os;
}
void print() { cout << "\n"; }
template <class Head, class... Tail>
void print(Head &&head, Tail &&... tail) {
cout << head;
if (sizeof...(Tail)) cout << " ";
print(forward<Tail>(tail)...);
}
void YES(bool t = 1) { print(t ? "YES" : "NO"); }
void NO(bool t = 1) { YES(!t); }
void Yes(bool t = 1) { print(t ? "Yes" : "No"); }
void No(bool t = 1) { Yes(!t); }
void yes(bool t = 1) { print(t ? "yes" : "no"); }
void no(bool t = 1) { yes(!t); }
template <typename T>
vector<T> cumsum(vector<T> &A) {
int N = A.size();
vector<T> B(N + 1);
B[0] = T(0);
FOR(i, N) { B[i + 1] = B[i] + A[i]; }
return B;
}
vc<int> bin_count(vi &A, int size) {
vc<int> C(size);
for (auto &x: A) { ++C[x]; }
return C;
}
template <typename T>
vector<int> argsort(vector<T> &A) {
vector<int> ids(A.size());
iota(all(ids), 0);
sort(all(ids),
[&](int i, int j) { return A[i] < A[j] || (A[i] == A[j] && i < j); });
return ids;
}
ll binary_search(function<bool(ll)> check, ll ok, ll ng) {
assert(check(ok));
while (abs(ok - ng) > 1) {
auto x = (ng + ok) / 2;
if (check(x))
ok = x;
else
ng = x;
}
return ok;
}
template <class T, class S>
inline bool chmax(T &a, const S &b) {
return (a < b ? a = b, 1 : 0);
}
template <class T, class S>
inline bool chmin(T &a, const S &b) {
return (a > b ? a = b, 1 : 0);
}
#define SUM(v) accumulate(all(v), 0LL)
#define MIN(v) *min_element(all(v))
#define MAX(v) *max_element(all(v))
#define LB(c, x) distance((c).begin(), lower_bound(all(c), (x)))
#define UB(c, x) distance((c).begin(), upper_bound(all(c), (x)))
#define UNIQUE(x) sort(all(x)), x.erase(unique(all(x)), x.end())
#line 2 "/home/maspy/library/graph/base.hpp"
template <typename T>
struct Edge {
int frm, to;
T cost;
int id;
};
template <typename T, bool directed = false>
struct Graph {
int N, M;
using cost_type = T;
using edge_type = Edge<T>;
vector<edge_type> edges;
vector<int> indptr;
vector<edge_type> csr_edges;
bool prepared;
class OutgoingEdges {
public:
OutgoingEdges(const Graph* G, int l, int r) : G(G), l(l), r(r) {}
const edge_type* begin() const {
if (l == r) { return 0; }
return &G->csr_edges[l];
}
const edge_type* end() const {
if (l == r) { return 0; }
return &G->csr_edges[r];
}
private:
int l, r;
const Graph* G;
};
bool is_prepared() { return prepared; }
constexpr bool is_directed() { return directed; }
Graph() {}
Graph(int N) : N(N), M(0), prepared(0) {}
void add(int frm, int to, T cost = 1, int i = -1) {
assert(!prepared);
assert(0 <= frm && frm < N && 0 <= to && to < N);
if (i == -1) i = M;
auto e = edge_type({frm, to, cost, i});
edges.eb(e);
++M;
}
void prepare() {
assert(!prepared);
prepared = true;
indptr.assign(N + 1, 0);
for (auto&& e: edges) {
indptr[e.frm + 1]++;
if (!directed) indptr[e.to + 1]++;
}
FOR(v, N) indptr[v + 1] += indptr[v];
auto counter = indptr;
csr_edges.resize(indptr.back() + 1);
for (auto&& e: edges) {
csr_edges[counter[e.frm]++] = e;
if (!directed)
csr_edges[counter[e.to]++] = edge_type({e.to, e.frm, e.cost, e.id});
}
}
OutgoingEdges operator[](int v) const {
assert(prepared);
return {this, indptr[v], indptr[v + 1]};
}
void debug() {
print("Graph");
if (!prepared) {
print("frm to cost id");
for (auto&& e: edges) print(e.frm, e.to, e.cost, e.id);
} else {
print("indptr", indptr);
print("frm to cost id");
FOR(v, N) for (auto&& e: (*this)[v]) print(e.frm, e.to, e.cost, e.id);
}
}
int size() { return N; }
};
#line 2 "/home/maspy/library/graph/centroid.hpp"
template <typename Graph, typename E = int>
struct CentroidDecomposition {
using edge_type = typename Graph::edge_type;
using F = function<E(E, edge_type)>;
Graph& G;
F f; // (E path value, edge e) -> E new_path_value
int N;
vector<int> cdep; // depth in centroid tree
vc<int> sz;
vc<int> par;
CentroidDecomposition(
Graph& G, F f = [](int x, edge_type e) { return x + e.cost; })
: G(G), N(G.N), f(f), sz(G.N), par(G.N), cdep(G.N, -1) {
build();
}
int find(int v) {
vc<int> V = {v};
par[v] = -1;
int p = 0;
while (p < len(V)) {
int v = V[p++];
sz[v] = 0;
for (auto&& e: G[v]) {
if (e.to == par[v] || cdep[e.to] != -1) continue;
par[e.to] = v;
V.eb(e.to);
}
}
while (len(V)) {
int v = V.back();
V.pop_back();
sz[v] += 1;
if (p - sz[v] <= p / 2) return v;
sz[par[v]] += sz[v];
}
return -1;
}
void build() {
assert(G.is_prepared());
assert(!G.is_directed());
int N = G.N;
vc<pair<int, int>> st = {{0, 0}};
while (len(st)) {
auto [lv, v] = st.back();
st.pop_back();
auto c = find(v);
cdep[c] = lv;
for (auto&& [frm, to, cost, id]: G[c]) {
if (cdep[to] == -1) st.eb(lv + 1, to);
}
}
}
vc<vc<pair<int, E>>> collect(int root, E root_val) {
/*
root を重心とする木において、(v, path data v) の vector を、方向ごとに集めて返す
・0 番目:root からのパスすべて(root を含む)
・i 番目:i 番目の方向
*/
vc<vc<pair<int, E>>> res = {{{root, root_val}}};
for (auto&& e: G[root]) {
int nxt = e.to;
if (cdep[nxt] < cdep[root]) continue;
vc<pair<int, E>> dat;
int p = 0;
dat.eb(nxt, f(root_val, e));
par[nxt] = root;
while (p < len(dat)) {
auto [v, val] = dat[p++];
for (auto&& e: G[v]) {
if (e.to == par[v]) continue;
if (cdep[e.to] < cdep[root]) continue;
par[e.to] = v;
dat.eb(e.to, f(val, e));
}
}
res.eb(dat);
res[0].insert(res[0].end(), all(dat));
}
return res;
}
};
#line 3 "main.cpp"
void solve() {
LL(N, K);
Graph<int> G(N);
FOR(_, N - 1) {
LL(a, b, c);
G.add(--a, --b, c);
}
G.prepare();
using T = pi;
// -1 : no color
// -2 : many color
auto f = [&](T t, auto e) -> T {
ll c = e.cost;
if (t.fi == -2) return t;
if (t.fi == c || t.se == c) return t;
if (t.fi == -1) t.fi = c;
elif (t.se == -1) t.se = c;
else t = {-2, -2};
if (t.se >= 0 && t.fi > t.se) swap(t.fi, t.se);
return t;
};
CentroidDecomposition<Graph<int>, T> CD(G, f);
ll ANS = 0;
FOR(root, N) {
auto dats = CD.collect(root, {-1, -1});
FOR(i, len(dats)) {
auto& dat = dats[i];
ll x0 = 0, x1 = 0, x2 = 0;
map<ll, ll> MP1;
map<pi, ll> MP2;
for (auto&& [v, p]: dat) {
if (p.fi == -2) continue;
if (p.fi == -1) x0 += 1;
elif (p.se < 0) {
++x1;
MP1[p.fi]++;
}
else {
++x2;
MP2[p]++;
}
}
ll x00 = 0, x01 = 0, x02 = 0, x11 = 0, x12 = 0, x22 = 0;
x00 = x0 * x0;
x01 = 2 * x0 * x1;
x02 = 2 * x0 * x2;
for (auto&& [v, p]: dat) {
if (p.fi < 0) continue;
if (p.se < 0) {
x11 += x1 - MP1[p.fi];
} else {
x12 += 2 * MP1[p.fi];
x12 += 2 * MP1[p.se];
x22 += MP2[p];
}
}
// ll x = x00 + x01 + x02 + x11 + x12 + x22;
ll x = x02 + x11 + x12 + x22;
ANS += (i == 0 ? x : -x);
}
}
print(ANS / 2);
}
signed main() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
cout << setprecision(15);
ll T = 1;
// LL(T);
FOR(_, T) solve();
return 0;
}
maspy