[国家集训队][bzoj 2152] 聪聪可可 [点分治]
题面:
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] 聪聪可可 [点分治]的更多相关文章
- 洛谷 P2634 BZOJ 2152 【模板】点分治(聪聪可可)
题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已 ...
- 【BZOJ 2152】 聪聪可可
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2152 [算法] 点分治 [代码] #include<bits/stdc++.h ...
- [bzoj2152][聪聪和可可] (点分治+概率)
Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...
- 【BZOJ 2152】聪聪可可 点分治
对于一棵树,fdrt找到重心,然后分治每个子树. 在一棵以重心为根的树上,符合条件的链是: 1.过重心(根) 2.不过重心 对于1我们只需dfs出距离重心(根)的距离然后统计再减去有重叠的边 对于2我 ...
- 「BZOJ 2152」聪聪可可
题目链接 戳这 \(Solution\) 这道题看起来就像点分治对吧.没错就是点分治. 什么是点分治 如果你不会点分治,可以去看看这儿 现在看到这里,首先确保你已经会了点分治,如果不会你还往下看,听不 ...
- BZOJ 2152:聪聪可可(树上点分治)
题目链接 题意 中文题意. 思路 和上一题类似,只不过cal()函数需要发生变化. 题目中要求是3的倍数,那么可以想到 (a + b) % 3 == 0 和 (a % 3 + b % 3) % 3 = ...
- BZOJ 2117: [2010国家集训队]Crash的旅游计划 动态点分治+二分
感觉现在写点分治可快了~ 二分答案,就可以将求第 $k$ 大转换成一个判断问题,直接拿点分树判断一下就行了. #include <cstdio> #include <vector&g ...
- bzoj 2152聪聪可可
2152: 聪聪可可 Time Limit: 3 Sec Memory Limit: 259 MB Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰 ...
- bzoj2152 / P2634 [国家集训队]聪聪可可(点分治)
P2634 [国家集训队]聪聪可可 淀粉质点分治板子 边权直接 mod 3 直接点分治统计出所有的符合条件的点对再和总方案数约分 至于约分.....gcd搞搞就好辣 #include<iostr ...
随机推荐
- Bootstrap历练实例:简单的可折叠
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- 零基础快速入门SpringBoot2.0 (一)
零基础快速入门SpringBoot2.0 (一) 一.SpringBoot2.x依赖环境和版本新特性说明 简介:讲解新版本依赖环境和springboot2新特性概述 1.依赖版本jdk8以上, Spr ...
- package.json字段分析
分析1.必须在包的顶层目录下2.二进制文件应该在bin目录下3.javascipt在lib目录下4.文档在doc目录下 package.json字段分析 name:包的名称,必须是唯一的,由小写英文字 ...
- C++大数问题
1.大数的加法 语法:add(char a[],char b[],char s[]); 参数: a[]:被加数,用字符串表示,位数不限 b[]:加数,用字符串表示,位数不限 s[]:结果,用字符串表示 ...
- vue axios请求频繁时取消上一次请求
一.前言 在项目中经常有一些场景会连续发送多个请求,而异步会导致最后得到的结果不是我们想要的,并且对性能也有非常大的影响.例如一个搜索框,每输入一个字符都要发送一次请求,但输入过快的时候其实前面的请求 ...
- ATM-core-src
from interface import bank, shopping, userfrom lib import common user_data = { 'name': None} def log ...
- 【PHP】根据两地经纬度计算距离
最近做一个H5活动的项目,有个要求是必须现场玩家才能参与,所以就需要计算玩家位置和活动地点的距离来判断是否在活动现场. 以下是写的一个根据经纬度计算两地距离的方法 1 function getDist ...
- STM32串口——中断方式的一般配置方法
#include "stm32f10x.h" /************************************************ 该程序讲解串口程序的一般配置方法: ...
- 扩展程序 - Google Chrome
Adblock Plus 3.0.3 Adblock Plus 已被超过 1 亿台设备使用,是世界上最受欢迎的广告拦截软件. ID:cfhdojbkjhnklbpkdaibdccddilifddb 查 ...
- J.U.C 系列之 Tools
JDK 5.0 开始,java并发大师Doug lea 为我们带来了更高效更应用的java并发API Java.util.concurrent包,简称J.U.C J.U.C 体系由如下五个知识结构构成 ...