题面:

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. Mybatis-延迟加载和缓存

    延迟加载 概念: 就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据.延迟加载也称懒加载. 好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表 ...

  2. os.walk 模块

    os.walk()可以得到一个三元tupple(dirpath, dirnames, filenames),其中第一个为起始路径,第二个为起始路径下的文件夹,第三个是起始路径下的文件. 其中dirpa ...

  3. 漫谈 Clustering (2): k-medoids

    上一次我们了解了一个最基本的 clustering 办法 k-means ,这次要说的 k-medoids 算法,其实从名字上就可以看出来,和 k-means 肯定是非常相似的.事实也确实如此,k-m ...

  4. android studio 安装以及遇到的一些问题

    1 安装 jkd ,版本一般是最新的,下怎么样的看一下自己电脑符合那种要求,可以去官网下 https://www.oracle.com/technetwork/java/javase/download ...

  5. 【组合数学】cf660E. Different Subsets For All Tuples

    比较套路的组合数学题 For a sequence a of n integers between 1 and m, inclusive, denote f(a) as the number of d ...

  6. Mysql主从数据同步cheksum问题

    做主从同步时出现问题,show slave status显示错误: Last_IO_Error: Got fatal error from master when reading data from ...

  7. tcl之基本语法—1

  8. php与js的crc32(支持中文)

    代码: <?php function myCrc32($string, $crc = 0) { $table = "00000000 77073096 EE0E612C 990951B ...

  9. JZOJ 3508. 【NOIP2013模拟11.5B组】好元素

    3508. [NOIP2013模拟11.5B组]好元素(good) (File IO): input:good.in output:good.out Time Limits: 2000 ms  Mem ...

  10. 42.VUE学习之--组件之子组件使用$on与$emit事件触发父组件实现购物车功能

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...