题面:

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

思路:

题目要求统计书上路径信息,想到树上分治算法

实际上这是一道点分治裸题,我就不瞎BB思路了,直接上做法。

对于一个节点,设dis[i]为其他节点到这个节点的距离 MOD 3

那么可以证明,一条经过该节点的合法路径(i,j),( dis[i] + dis[j] ) % 3==0

因此对每个节点求出其子树内的dis,经过该点的路径数即为(dis[i]==1的点数)*(dis[i]==2的点数)*2 + (dis[i]==0的点数)^2

递归求解

递归进入一个节点u时,ans先加入calc(u,0),即为上述求解过程(dis[u]==0开始)。

每一次对于当前递归到的节点的每一棵子树,ans先减去dis(v,e[i].w),即为从(dis[v]==e[i].w)开始,为的是去掉重复计算的部分。

求这个子树的重心

方法:

递归进入子树中每一个节点,统计其子最大的子树大小(包括连向其父节点的那一棵)

这个最大值最小的节点就是树的重心。

如果每次从这里进入,那么进入的子树的size一定小于整棵当前树的size的一半

这样递归下去最多log n层

求完这棵子树的重心以后从这个重心递归进入,求该子树的解

最后ans即为答案数目(ans初始为0)

Code:

 // luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
void _swap(int &x,int &y){x^=y;y^=x;x^=y;}
int _max(int x,int y){return (x>y)?x:y;}
inline int read(){
int re=,flag=;char ch=getchar();
while(ch>''||ch<''){
if(ch=='-') flag=-;
ch=getchar();
}
while(ch>=''&&ch<='') re=(re<<)+(re<<)+ch-'',ch=getchar();
return re*flag;
}
int n,cnt,ans,dis[],first[],tmp[],root,siz[],son[],sum;
bool vis[];
struct edge{
int to,next,w;
}a[];
inline void add(int u,int v,int w){
a[++cnt]=(edge){v,first[u],w};first[u]=cnt;
a[++cnt]=(edge){u,first[v],w};first[v]=cnt;
}
int gcd(int x,int y){return (y?gcd(y,x%y):x);};
void getroot(int u,int f){
//cout<<"getroot "<<u<<" "<<f<<"\n";
int i,v;
siz[u]=;son[u]=;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;
if(v==f||vis[v]) continue;
getroot(v,u);
siz[u]+=siz[v];
son[u]=_max(son[u],siz[v]);
}
son[u]=_max(son[u],sum-siz[u]);//统计父亲节点的那棵子树,sum为当前的整棵子树的size
//cout<<"finish getroot "<<son[u]<<'\n';
if(son[u]<son[root]) root=u;
}
void gettmp(int u,int f){
//cout<<"gettmp "<<u<<" "<<f<<"\n";
int i,v;
tmp[dis[u]]++;
for(i=first[u];~i;i=a[i].next){
v=a[i].to;
if(v==f||vis[v]) continue;
//cout<<" to "<<v<<'\n';
dis[v]=(dis[u]+a[i].w)%;
gettmp(v,u);
}
}
int calc(int u,int d){//即为文中描述的calc
dis[u]=d%;tmp[]=tmp[]=tmp[]=;
gettmp(u,);
return tmp[]*tmp[]*+tmp[]*tmp[];
}
void dfs(int u){
//cout<<"dfs "<<u<<"\n";
int i,v;
vis[u]=;ans+=calc(u,);
for(i=first[u];~i;i=a[i].next){
v=a[i].to;
if(vis[v]) continue;
ans-=calc(v,a[i].w);
sum=siz[v];root=;//更新root和sum
getroot(v,u);
dfs(root);
}
}
int main(){
// freopen("cckk.in","r",stdin);
// freopen("cckk.out","w",stdout);
memset(first,-,sizeof(first));
int i,t1,t2,t3;
n=read();
for(i=;i<n;i++){
t1=read();t2=read();t3=read();
add(t1,t2,t3);
}
//cout<<"finish read in\n";
sum=n;son[]=n;//将son[0]初始化为极大值
getroot(,);
dfs();
int div=gcd(n*n,ans);//注意约分
printf("%d/%d",ans/div,n*n/div);
}

[国家集训队][bzoj 2152] 聪聪可可 [点分治]的更多相关文章

  1. 洛谷 P2634 BZOJ 2152 【模板】点分治(聪聪可可)

    题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已 ...

  2. 【BZOJ 2152】 聪聪可可

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2152 [算法] 点分治 [代码] #include<bits/stdc++.h ...

  3. [bzoj2152][聪聪和可可] (点分治+概率)

    Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...

  4. 【BZOJ 2152】聪聪可可 点分治

    对于一棵树,fdrt找到重心,然后分治每个子树. 在一棵以重心为根的树上,符合条件的链是: 1.过重心(根) 2.不过重心 对于1我们只需dfs出距离重心(根)的距离然后统计再减去有重叠的边 对于2我 ...

  5. 「BZOJ 2152」聪聪可可

    题目链接 戳这 \(Solution\) 这道题看起来就像点分治对吧.没错就是点分治. 什么是点分治 如果你不会点分治,可以去看看这儿 现在看到这里,首先确保你已经会了点分治,如果不会你还往下看,听不 ...

  6. BZOJ 2152:聪聪可可(树上点分治)

    题目链接 题意 中文题意. 思路 和上一题类似,只不过cal()函数需要发生变化. 题目中要求是3的倍数,那么可以想到 (a + b) % 3 == 0 和 (a % 3 + b % 3) % 3 = ...

  7. BZOJ 2117: [2010国家集训队]Crash的旅游计划 动态点分治+二分

    感觉现在写点分治可快了~ 二分答案,就可以将求第 $k$ 大转换成一个判断问题,直接拿点分树判断一下就行了. #include <cstdio> #include <vector&g ...

  8. bzoj 2152聪聪可可

    2152: 聪聪可可 Time Limit: 3 Sec  Memory Limit: 259 MB Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰 ...

  9. bzoj2152 / P2634 [国家集训队]聪聪可可(点分治)

    P2634 [国家集训队]聪聪可可 淀粉质点分治板子 边权直接 mod 3 直接点分治统计出所有的符合条件的点对再和总方案数约分 至于约分.....gcd搞搞就好辣 #include<iostr ...

随机推荐

  1. linux 查看帐号创建时间

    查看用户的home目录的创建时间 查看日志 用stat 命令,可以看到目录的三个时间.不过这个时间只是用来参考的,确定一个范围. 查看日志是最准确的方法 /var/log/auth.log ,前提是你 ...

  2. Symfony相关网站参考

    http://www.doctrine-project.org/projects.html 数据库相关知识 http://firehare.blog.51cto.com/809276/703599整合 ...

  3. 操作系统(4)_进程同步_李善平ppt

    生产者进程count++是它的临界区,消费者count--是它的临界区. 经典同步问题,死锁问题,略.

  4. react与微信小程序

    由组员完成 原文链接 都说react和微信小程序很像,但是像在什么部分呢,待我稍作对比. 生命周期 1.React React的生命周期在16版本以前与之后发生了重大变化,原因在于引入的React F ...

  5. mount: no medium found on /dev/sr0 找不到介质

    在VMware虚拟机中配置yum源时,执行 mount /dev/cdrom /mnt/cdrom 出现 mount: no medium found on /dev/sr0. 首先在/mnt 目录下 ...

  6. Python中的tuple

    tuple_lst = [ ('元祖容器可哈希',), ('元祖中的元素不可直接修改',), ('元祖可迭代',), ('查',), ('练习',), ] 元祖容器可哈希 >>>ha ...

  7. mem_init()

    原本由bootmem管理的内存在mem_init函数中交由伙伴系统管理. 1.free_unused_memmap_node 相邻的membank间可能存在空洞,但在bootmem阶段这些空洞页也分配 ...

  8. Neon Lights in Hong Kong【香港霓虹灯】

    Neon Lights in Hong Kong Neon is to Hong Kong as red phone booths are to London and fog is to San Fr ...

  9. Compoer介绍

    Compoer介绍 Composer 是 PHP 的一个依赖管理工具.它允许你申明项目所依赖的代码库,它会在你的项目中为你安装他们. 安装Composer Composer.phar 是 Compos ...

  10. sql中比较大小

    if object_id('tempdb..#dataOldNew1') is not null drop table #dataOldNew1 select distinct store_cd ,i ...