圖片
核心:
感受又是一個樹形dp. dp[rt][k]:表示以rt爲根的樹中,到rt距離爲%2019=k的個數。 更新方式:來了一顆新樹x, rt這邊到rt距離爲d1的點,與x這邊到x距離爲d2的點,若(d1+d2+val)%2019==0, 則ans+=dp[rt][d1]*dp[val][d2],val表示rt與x之間的距離; 以後更新dp[rt][d], dp[rt][(d+val)%2019]+=dp[rt][d]
總結:
先求ans, 再更新dp[rt][d]
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct node {
int to;
int val;
};
const int N=2e4+3;
const int mod=2019;
int d[N][mod+3];
bool vis[N];
vector<node> g[N];
int n; LL ans;
void dfs(int rt) {
d[rt][0]+=1; // 重要
vis[rt]=1;
for (int i=0;i<g[rt].size();i++) {
int nxt=g[rt][i].to;
int val=g[rt][i].val;
if(vis[nxt]) continue;
dfs(nxt);
for(int k=0;k<mod;k++) {
int x=(mod*2-k-val)%mod;
ans+=d[nxt][x]*d[rt][k]; // 統一全部的距離是通過rt與nxt的一條路徑
}
for(int k=0;k<mod;k++)
d[rt][(k+val)%mod]+=d[nxt][k];
}
// 形式二 d[rt][0]+=1;
// ans+=d[rt][0]-1;
}
int main()
{
while(~scanf("%d",&n)) {
ans=0;
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
for (int i=0;i<N;i++)
g[i].clear();
for (int i=1;i<n;i++) {
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
// 個人傻逼錯誤
// if(a<b) swap(a,b); 這樣會改變圖的形狀
node tmp={b,c}; g[a].push_back(tmp);
tmp.to=a; g[b].push_back(tmp);
}
dfs(1);
printf("%lld\n",ans);
}
return 0;
}