题目略了吧,就是一棵树上有多少个点对之间的距离 \(\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. H3C进入目录---用户视图

    进入logfile文件目录 <H3C>cd logfile/        //进入目录 <H3C>pwd             //显示当前所属的目录 cf:/logfil ...

  2. 对象转json字符串案例

    测试对象与json字符串的转换 json字符串转对象 Stringstr = "{\"id\":\"1001\",\"name\" ...

  3. Linux 内核总线

    一个总线是处理器和一个或多个设备之间的通道. 为设备模型的目的, 所有的设备都通过 一个总线连接, 甚至当它是一个内部的虚拟的,"平台"总线. 总线可以插入另一个 - 一个 USB ...

  4. js实现new

    function New(fn,...args){ let obj={} obj.__proto__=fn.prototype let result=fn.apply(obj,args) if(typ ...

  5. windows编译caffe2遇到的问题

    首先介绍下window编译caffe2整体流程: 说明:如果不需要python支持只需3.4即可,而且编译亦不会出现问题. 1. 安装python2.7,. 我使用的是anaconda python2 ...

  6. dotnet 动态代理魔法书

    看到标题的小伙伴是不是想知道什么是魔法书,如果你需要写一段代码,这段代码是在做神奇的业务,只有你查询到了魔法书你才能找到这个对象,同时你还需要实现自己的接口,通过自己实现的接口调用才能用到有趣的方法 ...

  7. Hbase概念原理扫盲

    一.Hbase简介 1.什么是Hbase Hbase的原型是google的BigTable论文,收到了该论文思想的启发,目前作为hadoop的子项目来开发维护,用于支持结构化的数据存储. Hbase是 ...

  8. $hncpc2019E\ Numbers$ 搜索

    正解:搜索 解题报告: 传送门$QAQ$ 考虑直接搜所有长度为1的数的位置?然后其他就能确定了嘛$QwQ$ 设每个数的出现次数为$a_i$,状态数为$\prod_{i=0}^9(a_i+1) \le ...

  9. VBA工程密码破解

    如何破解VBA密码呢? ​ 见过网上很多关于破解VBA工程密码的方式,最常见的如下这种,但其实对于很多版本是不可行的. 基本都会提示“请先对VBA编码设置一个保护密码...” Sub VBAPassw ...

  10. BuilderPattern(建造者模式)-----Java/.Net

    建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式