题目链接

图片

核心:

感觉又是一个树形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;

}