Hunan Province in 2019 acm race I title (2019)

Topic link: https: //ac.nowcoder.com/acm/contest/1099/I

Title Description

  N has a weighted tree points, points are numbered 1, 2, ..., n have the tree. (N - 1) sides, the distance between two points seeking tree is a point to a multiple of the number 2019 ?

answer

  Counting point distance: Partition Point
  point cal partition function of the key is modified, other do not change substantially. How flexible use cal function, mainly to understand the meaning of several variables. The procedure of the partition point, the center of gravity is constantly looking for, and <1> obtained from each point to the center of gravity </ 2>, while with a temp array record these distances, then each sub-tree partition, the same procedure . Cal is the function after calculating <1>, temp to operate, how to change, depends on the specific topic. There is a point to note is <1> will operate from all points to the center of gravity also count (incoming center of gravity is added, there will be a zero), it will inevitably contain a temp len (len parameters are calc) . After completion of calculation is generally calc distance from a point to the other point, the distance of these points during the processing of the intermediate.
  cal change method

int cc[2019];
inline int calc(int x,int len)
{
    dis[x] = len;
    temp[0] = 0;//temp[0]记录temp数组的长度
    dfs(0,x);
    memset(cc,0,sizeof(cc));
    for(int i=1;i<=temp[0];i++)
        cc[temp[i]%2019]++;

    cc[0]--;
    int res=cc[0]*(cc[0]+1)/2;
    for(int i=1;i<=1009;i++)
        res+=cc[i]*cc[2019-i];
    return res;
}

  A multiple of 2019, it is easy to think of modulo process B is set to the center of gravity, A-> B + B-> C = 2019, it shows A-> C is a multiple of 2019.
  In fact, there is such a problem that double counting. Below by way of illustration, to explain how to deal with. Here Insert Picture Description
A center of gravity, the center of gravity to each point distance has been, but will function by cal B-> distance A and C-> A is also coupled, it is necessary to exclude this possibility, we end result is recorded for each divide and conquer different distances between the sub-tree, and the tree of the same sub-point between the need to exclude. How to exclude, ans- = cal (H, c ) to the sub-nodes of the H through H plus the distance to the point C, the answers need to be excluded.

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false)
const int N = 20020, INF = 0x7f7f7f7f;

int n,head[N*2],num,tot,ans;//tot记录当前子树点数
int dis[N],flag[N],temp[N];
//dis记录子树每一点到根节点的距离,flag用于删除根节点,temp总汇到根节点的距离
int size[N],Max[N],root;
struct edge
{
    int next,to,len;
} G[N*2];
void add(int from,int to,int len)
{
    G[++num].next=head[from];
    G[num].to=to;
    G[num].len=len;
    head[from]=num;
}
inline void input(void)
{
    for (int i=1; i<n; i++)
    {
        int x,y,v;
        cin>>x>>y>>v;
        add(x,y,v), add(y,x,v);
    }
}

inline void dp(int fa,int cur)//求树的重心
{
    size[cur] = 1, Max[cur] = 0;
    for (int i=head[cur]; i; i=G[i].next)
    {
        int v = G[i].to;
        if ( flag[v] || v == fa ) continue;
        dp(cur,v);
        size[cur] += size[v];
        Max[cur] = max( Max[cur], size[v] );
    }
    Max[cur] = max( Max[cur], tot - size[cur] );
    if ( Max[root] > Max[cur] ) root = cur;
}

inline void dfs(int fa,int cur)
{
    temp[ ++temp[0] ] = dis[cur];
    for (int i=head[cur]; i; i=G[i].next)
    {
        int v = G[i].to;
        if ( v == fa || flag[v] ) continue;
        dis[v] = dis[cur] + G[i].len;
        dfs(cur,v);
    }
}

int cc[2019];
inline int calc(int x,int len)
{
    dis[x] = len;
    temp[0] = 0;//temp[0]记录temp数组的长度
    dfs(0,x);
    memset(cc,0,sizeof(cc));
    for(int i=1;i<=temp[0];i++)
        cc[temp[i]%2019]++;

    cc[0]--;
    int res=cc[0]*(cc[0]+1)/2;
    for(int i=1;i<=1009;i++)
        res+=cc[i]*cc[2019-i];
    return res;
}

inline void divide(int x)
{
    flag[x] = true;//删去根节点
    ans += calc(x,0);
    //cout<<"ans="<<ans<<"\n";
    for (int i=head[x]; i; i=G[i].next)
    {
        int y = G[i].to;
        if ( flag[y] ) continue;
        ans -= calc(y,G[i].len);//点对在同一子树的情况
        tot = size[y], root = 0;
        dp(0,y);
        divide(root);
    }
}

inline void reset(void)
{
    num = 0;
    memset( head, 0, sizeof head );
    memset( flag, 0, sizeof flag );
    ans = 0, tot = n;
    root = 0, Max[0] = INF;
}

int main(void)
{
    IOS;
    while(cin>>n)
    {
        reset();
        input();
        dp(0,1);
        divide(root);
        cout<<ans<<"\n";
        //cout<<"\n";
    }
    return 0;
}
Published 41 original articles · won praise 2 · Views 1237

Guess you like

Origin blog.csdn.net/qq_41418281/article/details/101937149