洛谷P2634 [国家集训队]聪聪可可 点分治

和之前的模板题相比,只需要更改getdis这个函数即可,这个函数所做的处理是,求出以参数u为root时满足条件的情况数目。这里是问两点之间的距离是否能被3整除。所以直接讨论三种情况的数目就好了。

1、能整除3的路径数   用sum0计数

2、除3余1的路径数  用sum1计数

3、除3余2的路径数  用sum2计数

最后的答案就是sum1*sum2+sum2*sum1+sum3*sum3  /  n*n   再化简一下就是答案

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 20002
#define INF 2147483646
#define ll long long
using namespace std;
ll sum[3]; 
inline int gi()//输入挂 
{
  int date = 0,m = 1; char ch = 0;
  while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
  if(ch=='-'){m = -1; ch = getchar();}
  while(ch>='0' && ch<='9')
    {
      date = date*10+ch-'0';
      ch = getchar();
    }return date*m;
}
inline void write(ll qw) //输出挂 
{
  if(qw<0){putchar('-'); qw = -qw;}
  if(qw>9)write(qw/10);
  putchar(qw%10+'0');
}

struct node{int to,next,len;}t[2*maxn+5];
int head[maxn+5];
int sim[maxn+5],mxson[maxn+5];
bool vis[maxn+5];
int MX,root,summar;
ll ans;
int n,k,cnt,S;

void addedge(int u,int v,int l) //存图 
{
  cnt ++;
  t[cnt].to = v;
  t[cnt].next = head[u];
  t[cnt].len = l;
  head[u] = cnt;
  return;
}

void getroot(int u,int fa) //找重心函数 
{
  sim[u] = 1; mxson[u] = 0;
  for(int i = head[u];i;i = t[i].next)
    {
      int v = t[i].to;
      if(v == fa || vis[v])continue;
      getroot(v,u);
      sim[u] = sim[u] + sim[v];
      mxson[u] = max(sim[v],mxson[u]);
    }
  mxson[u] = max(mxson[u],S-sim[u]);
  if(mxson[u]<MX){root = u;MX = mxson[u];}
}

void getdis(int u,int fa,int dist) //计算多统计了的 子树中满足条件的情况 把到u点的距离存到dis数组里去 
{
  sum[dist%3]++;
  for(int i = head[u];i;i=t[i].next)
    {
      int v = t[i].to;
      if(vis[v]||v == fa)continue;
      getdis(v,u,(dist+t[i].len)%3);
    }
  return;
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
int consolate(int sta,int len1) //计算当前满足条件情况的数目 
{
  sum[0] = sum[1] = sum[2] = 0;
  getdis(sta,0,len1);
  ll now = 2*sum[1]*sum[2] + sum[0]*(sum[0]-1) + sum[0];
  return now;
}

void Divide(int tr) //分治函数 
{
  ans = ans + consolate(tr,0);
  vis[tr] = true;
  for(int i = head[tr];i;i = t[i].next)
    {
      int v = t[i].to;
      if(vis[v])continue;
      ans = ans - consolate(v,t[i].len);
      S = sim[v]; root = 0;
      MX = INF; getroot(v,0);
      Divide(root);
    }
  return;
}

int main()
{
  int u,v,l;
      n = gi();
      cnt = 0; memset(head,0,sizeof(head));
      for(int i = 1; i <= n - 1; i ++)
    {
      u = gi(); v = gi(); l = gi();
      addedge(u,v,l); addedge(v,u,l);
    }
      ans = 0;
      memset(vis,0,sizeof(vis));
      MX = INF ; S = n; getroot(1,0);
      Divide(root);
      ll gyz=gcd(n*n,ans);
      write(ans/gyz);putchar('/');write(n*n/gyz);
  return 0;
}
原文地址:https://www.cnblogs.com/wsblm/p/11202610.html