State Z is a underwater kingdom of the Atlantic Ocean. This country is amazing. There are nnn cities in the country and n−1n-1n−1 undirected underwater roads which connect all cities.
In order to save energy and avoid traffic congestion, the king promulgated a series of traffic regulations:
Residents have to travel on fish!
Residents need to feed the fish before you start your trip!The amount of food you feed the fish should be exactly the total distance of your journey.
What kind of food to feed depends on the total distance of your journey!Total distance is a multiple of three. You should feed the fish with Durian. Total distance modulus 333 equaling 111. It should be Papaya.Total distance modulus 333 equaling 222. It should be Avocado!!!
Sure, fish like to eat these fruits very much.
Today is the first day of the king's decree. Because the residents here are not good at mathematics, they don't know how much fruit they need to give fish to go to other cities. So the king give an order to the energy minister Ynaonlctrm From all cities to all cities directly, which means that he will make n∗(n−1)n*(n-1)n∗(n−1) trips.
For example, A - (5 mile) - B - (5 mile) - C, he needs to run the fish, starting at A, passing B, finally arriving C (papaya 10 kg), also he needs to start at C and end at A (papaya 10 kg). Indirect passage is useless. "I've passed City B, my dear emperor." "Oh! It's no use! Not directly! People in cities will never know how much the fish need to eat! The fish will surely die!!! You also need to take several trips which start at B or end with B!" The Emperor said.
It's really a tough task. Can you help him figure out how much fruit he needs to prepare for the emperor's mission?
Input
Multiple input!
Fist line is NNN. next N−1N-1N−1 line has three integer aaa, bbb and ccc. It represent city aaa and city bbb is connected by a road of ccc nautical miles. (1<n≤1041<n \le 10^41<n≤104, 0≤a,b<n0 \le a,b<n0≤a,b<n, 1≤c<1051 \le c<10^51≤c<105, ∑n≤105\sum{n} \le 10^5∑n≤105)
Output
For each data, output three number, the amount of Durian, Papaya and Avocado he need. (the result could be very large, please output the result mod 109+710^9+7109+7)
Solution:
看着队友OJ的代码学的点分治。
这真是一个牛逼的算法
每次取重心作为树根,分治再利用容斥去重。每个solve函数实际是一个合并的过程
参考 https://blog.csdn.net/qq_39553725/article/details/77542223
AC Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = static_cast<const int>(2e4 + 5);
const int MOD = static_cast<const int>(1e9 + 7);
struct Edge {
int v, w;
Edge(int v = 0, int w = 0) : v(v), w(w) {}
};
typedef long long ll;
inline ll sub(ll a, ll b) { return (a - b + MOD) % MOD; }
inline ll add(ll a, ll b) { return (a + b) % MOD; }
inline ll multiply(ll a, ll b) { return (a * b + MOD) % MOD; }
int n, _root, maxSize[maxn], treeSize, _size[maxn];
bool vis[maxn];
int dis[maxn], disFromRoot[maxn], r, num[4];
ll ans[4];
int bucket[4];
vector<Edge> graph[maxn];
void add_edge(int u, int v, int w) {
graph[u].emplace_back(v, w);
}
void getRoot(int u, int pr) {
_size[u] = 1;
maxSize[u] = 0;
for (auto next: graph[u]) {
int v = next.v;
if (vis[v] || v == pr)
continue;
getRoot(v, u);
_size[u] += _size[v];
maxSize[u] = max(maxSize[u], _size[v]);
}
maxSize[u] = max(maxSize[u], treeSize - _size[u]);
if (maxSize[u] < maxSize[_root]) _root = u;
}
void getDis(int u, int pr) {
dis[++r] = disFromRoot[u];
for (auto next: graph[u]) {
int v = next.v, w = next.w;
if (vis[v] || v == pr) continue;
disFromRoot[v] = disFromRoot[u] + w;
getDis(v, u);
}
}
void solve(int curr, int w, int k) {
disFromRoot[curr] = w;
r = 0;
getDis(curr, 0);
//扔进mod3的桶里 防超时
for (int i = 1; i <= r; ++i)
bucket[dis[i] % 3] = (bucket[dis[i] % 3] + dis[i]) % MOD;
// cout << "curr:" << curr << " k: " << k << endl;
// for (int i = 0; i < 3; ++i)
// cout << bucket[i] << " ";
// cout << endl;
for (int i = 1; i <= r; ++i)
for (int j = 0; j < 3; ++j)
//ans[dis[i]+bucket[j]] += dis[i] + bucket[j] 每个节点都累加一遍
// ans[(dis[i] + j) % 3] = ((ans[(dis[i] + j) % 3] + (dis[i] + bucket[j]) % MOD * k % MOD) % MOD + MOD) % MOD;
ans[(dis[i] + j) % 3] = add(ans[(dis[i] + j) % 3], multiply(add(dis[i], bucket[j]), k));
// cout << "change: ans[" << (dis[i] + j) % 3 << "] : " << k * (add(dis[i], bucket[j])) << "("
// << dis[i] << "," << bucket[j] << ")" << endl;
// cout << "--------" << endl;
// cout << "after change" << endl;
// for(int i = 0; i < 3; ++i)
// cout << ans[i] << " ";
// cout << endl;
// cout << "--------" << endl;
//清桶
memset(bucket, 0, sizeof(bucket));
}
void divide(int u) {
vis[u] = true;
solve(u, 0, 1);
for (auto next: graph[u]) {
int v = next.v, w = next.w;
if (vis[v]) continue;
solve(v, w, -1);
_root = 0;
treeSize = _size[v];
getRoot(v, u);
divide(_root);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
while (cin >> n) {
int u, v = 0, w = 0;
for (int _ = 1; _ < n; ++_) {
cin >> u >> v >> w;
u++;
v++;
add_edge(u, v, w);
add_edge(v, u, w);
}
for (int i = 0; i < 3; ++i) num[i] = i, ans[i] = 0;
maxSize[0] = treeSize = n;
getRoot(1, 0);
divide(_root);
for (int i = 0; i < 3; ++i)
ans[i] = multiply(ans[i], 2);
for (int i = 0; i < 3; ++i) {
if (i)
cout << " ";
cout << ans[i];
}
cout << endl;
for (int i = 0; i <= n; ++i)
graph[i].clear();
memset(vis, false, (n + 1) * sizeof(bool));
}
return 0;
}