3ヶ月間に見えたこのタイトルは、最終的には木がDPを学ぶことがなかったときに表示するために初めて、点線のルールをしたいと思い、持っていたが、しません
その後、我々は2回目のスキャン、少し考え方を学びました。。。。
物事はそれの形而上学に本当にしていること。。。
書式#include <iostreamの> 書式#include <CStringの> 書式#include <ベクトル> 書式#include <アルゴリズム> 名前空間stdを使用。 長い長いLLのtypedef。 const int型MAXN = 1E5 + 7。 CONST LL MOD = 1E9 + 7。 構造体ノード{ int型のp; LLのlen; ノード(INT _p、LL _len):P(-P)、手段(_len){} }。 int型のn; LL DP [MAXN] [5]。 LL CNT [MAXN] [6]。 ベクター<ノード> G [MAXN]。 ボイド挿入(であるINT、INT EN、LL LEN){ G .push_back(ノード(EN、LEN))です]。 } DFS2あなたは{(あなたが得る、あなたはFA) 以下のために(INT I 0 =; I <G [X] .size(); iが++){ INT P = G [X] [I] .P。 LL LEN = G [X] [I] .LEN。 継続した(p == FA)であれば、 DFS2(P、x)は、 {ため(++; <3 = 0の整数) DP [X] [(A + LEN)%3] + =(DP [P] [A] + CNT [P] [A] * LEN)%MOD。 CNT [X] [(A + LEN)%3] + = CNT [P] [A]。 DP [X] [(A + LEN)%3]%= MOD。 } DP [X] [わずか3%] + =のみ。 dp[x][len % 3] %= mod; cnt[x][len % 3] ++; } return 0; } ll ans[10]; ll son[10]; int dfs(int x, int fa) { for (int i = 0; i < G[x].size(); i++) { int p = G[x][i].p; ll len = G[x][i].len; if (p == fa) continue; for (int a = 0; a < 3; a++) { ans[(a + len) % 3] = (dp[x][(a + len) % 3] - (cnt[p][a] * len + dp[p][a])) % mod; ans[(a + len) % 3] += mod; ans[(a + len) % 3] %= mod; son[(a + len) % 3] = cnt[x][(a + len) % 3] - cnt[p][a]; } son[len % 3]--; ans[len % 3] = (ans[len % 3] - len + mod) % mod; //删除了多的边 for (int a = 0; a < 3; a++) { dp[p][(a + len) % 3] += (ans[a] + son[a] * len) % mod; dp[p][(a + len) % 3] %= mod; cnt[p][(a + len) % 3] += son[a]; } cnt[p][len % 3]++; dp[p][len % 3] += len; dp[p][len % 3] %= mod; dfs(p, x); } return 0; } int main() { while (~scanf("%d", &n)) { for (int i = 0; i <= n; i++) G[i].clear(); memset(dp, 0, sizeof(dp)); memset(cnt, 0, sizeof(cnt)); int be, en; ll len; for (int i = 1; i < n; i++) { scanf("%d %d %lld", &be, &en, &len); insert(be, en, len); insert(en, be, len); } dfs2(0, -1); dfs(0, -1); ll a = 0, b = 0, c = 0; for (int i = 0; i < n; i++) { a = (a + dp[i][0]) % mod; b = (b + dp[i][1]) % mod; c = (c + dp[i][2]) % mod; } printf("%lld %lld %lld\n", a, b, c); } return 0; }