学习笔记:点分治
时间:2021-08-17
本文章向大家介绍学习笔记:点分治,主要包括学习笔记:点分治使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
【题目】
-
看了上面的题目,想必有很多种算法解决。
-
\(1\)、枚举不同的两个点,然后\(dfs\)算出之间的距离,判断一下就行了。时间复杂度大概是\(O(n^3)\)。
-
\(2\)、选一个节点做树的根,求出每个点的深度。然后枚举两个点,求\(lca\),简单加减一下就行了。时间复杂度大概是\(O(n^2logn)\)。
-
\(3\)、时间复杂度为\(O(nlogn)\)的算法点分治。
【点分治算法】
- 点分治要我们每次选择一个点\(A\),处理有关点\(A\)的路径,然后将点\(A\)删除,然后重复以上过程。
第一步:找重心
- 选择哪个点成为点\(A\)也是有学问的,选的不同会影响遍历的效率。
-
显然选\(y\)比选\(x\)不优,选\(x\)最多递归\(2\)层,选\(y\)最多递归\(4\)层。
-
所以,点\(A\)应该是当前子树的重心(重心所有的子树大小的最大值小于整个树大小的一半)。
第二步:求距离
-
有关点\(A\)的路径无非就两种情况。
- 点\(A\)为链首,点\(A\)的子树上另外一点为链尾
- 点\(A\)其中一个子树上的点为链首,点\(A\)另外一棵子树上的点为链尾,绕过点\(A\)
-
我们对重心的子树逐一处理\(\Longrightarrow\)就是先处理完一个子树,再处理另一个子树。
-
先算出当前子树第\(i\)号节点到点\(A\)的距离\(d_i\),然后我们在桶里面查找\(k-d_i\),若找到了,便结束了。
-
当前子树查找完了以后,便将\(d_i\)丢进桶里。
-
切忌一边查找一边将\(d_i\)丢进桶里
-
处理完所有子树,便在桶里查找\(k\),代表寻找子树中是否有一点与点\(A\)距离为\(k\)。
第三步:递归
- 在\(A\)的子树进行上述操作。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int INF=2147483647;
const int N=10100;
int n,m,b[N];
bool ans[N];
struct EDGE
{
int v,w,nx;
}lb[N<<1];
int tot=1,top[N];
void add(int u,int v,int w)
{
lb[++tot]=(EDGE){v,w,top[u]};
top[u]=tot;
}
bool vis[N];
int siz[N],masiz[N],q[N],he,ta;
void dfs0(int u)
{
q[++ta]=u,vis[u]=1;
siz[u]=1,masiz[u]=0;
for(int i=top[u]; i; i=lb[i].nx)
{
int v=lb[i].v;
if(vis[v]) continue;
dfs0(v);
siz[u]+=siz[v];
masiz[u]=max(masiz[u],siz[v]);
}
vis[u]=0;
}
int d[N];
void dfs1(int u)
{
q[++ta]=u,vis[u]=1;
for(int i=top[u]; i; i=lb[i].nx)
{
int v=lb[i].v,w=lb[i].w;
if(vis[v]) continue;
d[v]=d[u]+w;
dfs1(v);
}
vis[u]=0;
}
bool t[10000010];
void calc(int l,int r)
{
for(int i=l; i<=r; i++)
{
int u=q[i];
for(int j=1; j<=m; j++)
if(b[j]>=d[u])ans[j]|=t[b[j]-d[u]];
}
for(int i=l; i<=r; i++)
if(d[q[i]]<=1e7)t[d[q[i]]]=1;
}
void clear()
{
for(int i=1; i<=ta; i++)
if(d[q[i]]<=1e7)t[d[q[i]]]=0;
}
void solve(int u)
{
he=1,ta=0,dfs0(u);
int mi=INF,s=siz[u];
for(int i=1; i<=ta; i++)
{
int v=q[i],g=max(masiz[v],s-siz[v]);
if(g<mi) mi=g,u=v;
}
he=1,ta=0;
d[u]=0,vis[u]=1;
for(int i=top[u]; i; i=lb[i].nx)
{
int v=lb[i].v,w=lb[i].w;
if(vis[v])continue;
d[v]=d[u]+w;
dfs1(v);
calc(he,ta);
he=ta+1;
}
q[++ta]=u;
calc(he,ta);
clear();
for(int i=top[u]; i; i=lb[i].nx)
{
int v=lb[i].v;
if(vis[v]) continue;
solve(v);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i< n; i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,w),add(y,x,w);
}
for(int i=1; i<=m; i++)scanf("%d",&b[i]);
solve(1);
for(int i=1; i<=m; i++)
if(ans[i])printf("AYE\n");
else printf("NAY\n");
return 0;
}
原文地址:https://www.cnblogs.com/zeromclai/p/15152591.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 随机点名系统——html初学实战
- Centos 7 使用 rpm 安装 JDK 1.8
- PAT (Advanced Level) Practice 1145 Hashing - Average Search Time (25分)
- Centos 7使用 rpm 安装 MySQL 5.7
- Leetcode 300. 最长上升子序列(n方dp,nlogn贪心+二分查找)
- select 进阶查询
- Codeforces Round #627 (Div. 3) E. Sleeping Schedule (DP)
- PAT (Advanced Level) Practice 1144 The Missing Number (20分)
- JDBC 基础操作
- Codeforces Round #625 (Div. 2, based on Technocup 2020 Final Round) C. Remove Adjacent
- MySQL 存储过程
- MySQL 约束
- MySQL 中的流程控制语句
- MySQL 权限操作
- MySQL 事务