聪聪可可 HYSBZ - 2152

本文介绍了一种利用点分治解决特定图论问题的方法,该问题要求计算图中所有有序点对之间的距离,且这些距离必须是3的倍数。通过寻找图的重心并递归地将问题分解为子问题,最终实现高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题:https://www.lydsy.com/JudgeOnline/problem.php?id=2152

思路:要求求距离为3的倍数的所有有序点对,可以点分治,对于每一个子树找到重心计算到他距离为0,1,2的点的个数,统计求和

#include<bits/stdc++.h>
#define read(x) scanf("%d",&x)
using namespace std;
const int inf=1e9;
const int maxn=2e5;
typedef long long LL;
struct edge{
    int to;
    int next;
    int v;
}e[maxn*2];
int n,cnt,ans,root,sum;
int last[maxn],son[maxn],f[maxn],d[maxn],t[5];
bool vis[maxn];
int gcd(int a,int b) {
    if(b==0) return a;
    else return gcd(b,a%b);
}
void addedge(int u,int v,int w) {
    e[++cnt].to=v;
    e[cnt].next=last[u];
    e[cnt].v=w;
    last[u]=cnt;
    e[++cnt].to=u;
    e[cnt].next=last[v];
    e[cnt].v=w;
    last[v]=cnt;
}
void getroot(int x,int fa) {
    son[x]=1;
    f[x]=0;
    for(int i=last[x];i;i=e[i].next) {
        if(!vis[e[i].to] && e[i].to != fa) {
            getroot(e[i].to,x);
            son[x]+=son[e[i].to];
            f[x]=max(f[x],son[e[i].to]);
        }
    }
    f[x]=max(f[x],sum-son[x]);
    if(f[x]<f[root]) root=x;
}
void getdeep(int x,int fa) {
    t[d[x]]++;
    for(int i=last[x];i;i=e[i].next) {
        if(!vis[e[i].to] && e[i].to != fa) {
            d[e[i].to]=(d[x]+e[i].v)%3;
            getdeep(e[i].to,x);
        }
    }
}
int cal(int x,int now) {
    t[0]=t[1]=t[2]=0;
    d[x]=now;
    getdeep(x,0);
    return t[1]*t[2]*2+t[0]*t[0];
}
void work(int x) {
    ans+=cal(x,0);
    vis[x]=1;
    for(int i=last[x];i;i=e[i].next) {
        if(!vis[e[i].to]) {
            ans-=cal(e[i].to,e[i].v);
            root=0;
            sum=son[e[i].to];
            getroot(e[i].to,0);
            work(root);
        }
    }
}
int main() {
    read(n);
    int u,v,w;
    for(int i=1;i<n;i++) {
        read(u);
        read(v);
        read(w);
        w=w%3;
        addedge(u,v,w);
    }
    f[0]=sum=n;
    getroot(1,0);
    work(root);
    int t=gcd(ans,n*n);
    printf("%d/%d\n",ans/t,n*n/t);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值