题面:

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. SSH框架快速搭建(Maven)

    1.新建Maven项目ssh 2.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=& ...

  2. Drupal的入门学习

    1. 注意content中的区别 Article和Basic page的区别 a.输入字段不一样,Article内容多了两个字段:tag和图片. b.内容的默认设置不一样,Article默认允许评论, ...

  3. BundleConfig的作用

    在ASP.NET MVC4中(在WebForm中应该也有),有一个叫做Bundle的东西,它用来将js和css进行压缩(多个文件可以打包成一个文件),并且可以区分调试和非调试,在调试时不进行压缩,以原 ...

  4. MySQL数据库 crud语句 ifnull() 创建新账户 备份数据库 一对多关系 多对多(中间表) 外键约束 自关联 子查询注意事项 DML DDL DQL mysql面试题 truncate与delete的区别

    DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 DDL ...

  5. linux系统串口编程实例

    在嵌入式开发中一些设备如WiFi.蓝牙......都会通过串口进行主机与从机间通信,串口一般以每次1bit位进行传输,效率相对慢. 在linux系统下串口的编程有如下几个步骤,最主要的是串口初始化! ...

  6. SAP 日志管理

    现在项目上自开发的dialog程序越来越多,有很多敏感数据需要像SAP标准的业务一样,能看到所有的修改日志,要想实现日志的功能,有以下几个办法: 办法一.建一个日志表,在原有表的基础上,加上日期和时间 ...

  7. Springboot 入门创建hello world1!

    1.首先使用工具是Eclipse,安装插件,点击“Help”-“Eclipse Marketplace...”, 一步步直接Ok,等待安装完成 2.创建Springboot项目 到此 就创建成功了 3 ...

  8. Centos7之WEB服务器

    1.安装httpd服务 输入命令:yum -y install httpd [root@N37012 ~]# yum -y install httpc Loaded plugins: fastestm ...

  9. linux正则表达式企业级深度实践案例2

    [root@redhat~]#  sed  -nr  ' s#([ ^ : ]+)  (: .* :)  (/.*$)#\3\2\1#gp '  /etc/passwd

  10. Android Studio 安装与使用ADB wifi 无线调试

    首先,安装ADB WIFI File->Settings->Plugins 其次,用USB连接手机与电脑(并开启手机的调试模式) 任务栏若无提示,即可拔下USB线,开始无线调试 任务栏若是 ...