题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\)

\(n \leq 40000\)


算法##

首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它点到这个点的距离,统计一下即可。

但是这样太慢了。于是考虑“分治”这种神奇的做法。

第一步,选一个点做根节点,这个点便是树的重心(代码中找重心 \(getroot\) ),它满足每棵子树节点数不超过 \(n/2\) ,即可保证子问题规模减半。

第二步,寻找所有经过根节点的路径,这些路径可以写成 \(u \leadsto rt + v \leadsto rt\)

但是这样有一个问题,\(u\) 和 \(v\) 的 \(lca\) 可能不是 \(rt\) ,即 \(u \leadsto v\) 不经过 \(rt\)

于是我们用容斥原理,枚举 \(rt\) 的每一个儿子把这种情况减去(代码 \(work\) 中的 $ ans-=cal(v,p \to len)$)

顺便提一句如何计算有多少小于 \(k\) 的路径,两个指针扫来扫去就行了(代码中的 \(cal\) )

复杂度 \(O(n)\)

第三步,对于 \(rt\) 的每一棵子树进行递归(第一步)。


分析##

个人认为算法的重点有两个:

  1. \(cal\) 复杂度可为 \(O(n)\)

    2.重心可使每棵子树规模减半

    这样就使得整个算法复杂度为 \(O(nlogn)\)

代码##

终于会点分治了,很开心啊~

#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; const int N = 40005; struct node{
node *next;
int v,len;
}pool[N*2],*h[N];
int cnt;
void addedge(int u,int v,int len){
node *p=&pool[++cnt],*q=&pool[++cnt];
p->v=v;p->next=h[u];h[u]=p;p->len=len;
q->v=u;q->next=h[v];h[v]=q;q->len=len;
} int sum,rt,n,k;
int size[N],mx[N],vis[N];
void getroot(int u,int f){
int v;
size[u]=1; mx[u]=0;
for(node *p=h[u];p;p=p->next){
if(vis[v=p->v] || v==f) continue;
getroot(v,u);
size[u]+=size[v]; mx[u]=max(mx[u],size[v]);
}
mx[u]=max(mx[u],sum-size[u]);
if(mx[u]<mx[rt]) rt=u;
} int dep[N],dd;
void getdeep(int u,int f,int c){
int v;
dep[++dd]=c;
size[u]=1;
for(node *p=h[u];p;p=p->next){
if(vis[v=p->v] || v==f) continue;
getdeep(v,u,c+p->len);
size[u]+=size[v];
}
}
int cal(int u,int c){
int t=0;
dd=0;
getdeep(u,0,c);
sort(dep+1,dep+1+dd);
for(int l=1,r=dd;l<r;l++){
while(l<r && dep[l]+dep[r]>k) r--;
t+=r-l;
}
return t;
} int ans;
void work(int u){
int v;
vis[u]=1;
ans+=cal(u,0);
for(node *p=h[u];p;p=p->next){
if(vis[v=p->v]) continue;
ans-=cal(v,p->len); rt=0; sum=size[v]; getroot(v,u);
work(rt);
}
} int main()
{
int u,v,l;
scanf("%d",&n);
for(int i=1;i<n;i++){
scanf("%d%d%d",&u,&v,&l);
addedge(u,v,l);
}
scanf("%d",&k); mx[0]=400005;
rt=0; sum=n; getroot(1,0);
work(rt);
printf("%d\n",ans); return 0;
}

[洛谷P4178] Tree (点分治模板)的更多相关文章

  1. 洛谷P4178 Tree (点分治)

    题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式:   N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下 ...

  2. 洛谷 P4178 Tree —— 点分治

    题目:https://www.luogu.org/problemnew/show/P4178 这道题要把 dep( dis? ) 加入一个 tmp 数组里,排序,计算点对,复杂度很美: 没有写 sor ...

  3. POJ1471 Tree/洛谷P4178 Tree

    Tree P4178 Tree 点分治板子. 点分治就是直接找树的重心进行暴力计算,每次树的深度不会超过子树深度的\(\frac{1}{2}\),计算完就消除影响,找下一个重心. 所以伪代码: voi ...

  4. 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...

  5. 2018.07.20 洛谷P4178 Tree(点分治)

    传送门 又一道点分治. 直接维护子树内到根的所有路径长度,然后排序+双指针统计答案. 代码如下: #include<bits/stdc++.h> #define N 40005 using ...

  6. 洛谷 4178 Tree——点分治

    题目:https://www.luogu.org/problemnew/show/P4178 点分治.如果把每次的 dis 和 K-dis 都离散化,用树状数组找,是O(n*logn*logn),会T ...

  7. 洛谷P4178 Tree (算竞进阶习题)

    点分治 还是一道点分治,和前面那道题不同的是求所有距离小于等于k的点对. 如果只是等于k,我们可以把重心的每个子树分开处理,统计之后再合并,这样可以避免答案重复(也就是再同一个子树中出现路径之和为k的 ...

  8. [洛谷P4178]Tree

    题目大意:给一棵树,问有多少条路径长度小于等于$k$ 题解:点分治 卡点:无 C++ Code: #include <cstdio> #include <algorithm> ...

  9. 洛谷 P4178 Tree

    #include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #inclu ...

随机推荐

  1. 2019-3-8-为何使用-DirectComposition

    title author date CreateTime categories 为何使用 DirectComposition lindexi 2019-3-8 8:56:9 +0800 2018-04 ...

  2. python字符串(str)

    # value = "raitOrEi" # v = value.capitalize()#首字母大写 # print(v) # v1 = v.casefold()#全部变小写,不 ...

  3. 9.python入门

    借鉴:https://www.cnblogs.com/wupeiqi/articles/5433925.html 一.HelloWorld print("HelloWorld") ...

  4. 最近邻分类器,K近邻分类器,线性分类器

    转自:https://blog.csdn.net/oldmao_2001/article/details/90665515 最近邻分类器: 通俗来讲,计算测试样本与所有样本的距离,将测试样本归为距离最 ...

  5. java后台防止sql注入的方法

    1.采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setString方法传值即可: String sql= "select * from users where usernam ...

  6. TCP/IP Basic

    1.概述 TCP/IP起源于60年代美国政府遮住的一个分组交换网络项目,在当今被定义为互联网通信接口,TCP/IP主要分为4层,每一层负责不同的通信功能,这促成了一个协议族的诞生,而TCP/IP是一组 ...

  7. windows7下mysql8.0.18部署安装

    一.前期准备(windows7+mysql-8.0.18-winx64) 1.下载地址:https://dev.mysql.com/downloads/ 2.选择直接下载不登录账号,下载的压缩包大概两 ...

  8. 基于FPGA的SPI FLASH控制器设计

    1.SPI FLASH的基本特征 本文实现用FPGA来设计SPI FLASH,FLASH型号为W25Q128BV.支持3种通信方式,SPI.Dual SPI和Quad SPI.FLASH的存储单元无法 ...

  9. 为什么使用kotlin可以节省开发时间

    前言:.kotlin是一门语言,光靠一篇文章要入门不太现实,所以这篇文章重点讲的是kotlin相对于java的一些特性和这些特性带来的好处. 一.简单介绍 Kotlin 是一种在 Java 虚拟机上运 ...

  10. $CH$3801 $Rainbow$的信号 期望+位运算

    正解:位运算 解题报告: 传送门! 其实就是个位运算,,,只是顺便加了个期望的知识点$so$期望的帕并不难来着$QwQ$ 先把期望的皮扒了,就直接分类讨论下,不难发现,答案分为两个部分 $\left\ ...