题目略了吧,就是一棵树上有多少个点对之间的距离 \(\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. PC端网页特效

    元素偏移量offset系列 offset翻译过来就是偏移量,我们使用offset系列相关属性可以动态的得到该元素的位置(偏移),大小等 获得元素距离带有定位父元素的位置 获得元素自身的大小(宽度高度) ...

  2. ES6必须 知道的小知识

    1.函数的默认参数 一般 我们给函数设置默认参数的时候  会在函数里用 || 运算符 比如 function show(width,height ....){ var height = height ...

  3. 复盘:错误理解zuul路径匹配,无法使用zuul

    场景: 项目中用到zuul时,配置url总是有问题,无法路由到对应微服务. 配置如下: zuul: routes: m2-member: path: /member/* serviceId: m2-m ...

  4. 聊聊固态硬盘1--人生头两块SSD

    第一块固态硬盘--浦科特m6s   来源:京东双11   价格:319rmb           第二款固态--饥饿鲨ocz arc100   来源:美国亚马逊 黑色星期五 价格:366rmb     ...

  5. echarts拓扑图(graph,力导向布局图)

    echarts连接:https://gallery.echartsjs.com/editor.html?c=xCLEj67T3H 讲解:https://www.cnblogs.com/koala201 ...

  6. Effective TestStand Operator Interfaces

    目录 为什么要使用操作员界面? 是什么决定一个好的界面? 用户的类型 和 界面的必要元素 TestStand 架构 TestStand 自带的例子 自定义用户界面 TestStand 提供的三个管理控 ...

  7. Java并发编程系列-(8) JMM和底层实现原理

    8. JMM和底层实现原理 8.1 线程间的通信与同步 线程之间的通信 线程的通信是指线程之间以何种机制来交换信息.在编程中,线程之间的通信机制有两种,共享内存和消息传递. 在共享内存的并发模型里,线 ...

  8. 小白学 Python 爬虫(30):代理基础

    人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前置准备(一)基本类库的安装 小白学 Python 爬虫(3):前置准备(二)Li ...

  9. poj1737-----这题有毒

    这题有毒,不取模还会溢出,我哭了 <进阶指南>p337动态规划 公式就是个这了,代码就不贴了,反正是错的,用java算了

  10. PAC 代理自动发现简介

    一 简介 1.1 什么是PAC文件 代理自动配置(PAC)文件包含一组用javaScript编码的规则,允许web浏览器确定是将Web流量直接发送到Internet还是通过代理服务器发送        ...