当前位置: 首页 > news >正文

点分治学习笔记

怎么感觉这是个玄学算法

基础思路

对于一个以 \(u\) 为根节点的子树内,其所有路径可以分为两类:

1.经过 \(u\) 点的

2.不经过 \(u\) 点的

所以我们可以进行分治,进行深搜,对于每一个点处理经过自己的,然后去深搜解决其子节点

但是这样的算法对于链状的树就炸了,处理自己的 \(O(n)\) , 深搜 \(O(n)\) ,时间复杂度会退化到 \(O(n^2)\)

所以不妨每次找到重心作为根节点,然后再处理

然后我们就得到了淀粉质

例题

这里

考虑对于每个点,应该怎么计算经过它的合法路径长度

我们可以跑出字数内每个点到当前节点的距离,排序后扫一遍双指针,扫出所有距离和在给定区间内的点对

(在代码中,利用了容斥原理,\(counter\) 函数表示所有距离不小于 \(lim\) 的点对)

但是这样会发现同一个子节点的子树内的点也会被计算进去,所以提前减掉即可

代码
#include<bits/stdc++.h>
#define usetime() (double)clock () / CLOCKS_PER_SEC * 1000.0
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
const int inf=2e9+1;
void read(int& x){char c;bool f=0;while((c=getchar())<48) f|=(c==45);x=c-48;while((c=getchar())>47) x=(x<<3)+(x<<1)+c-48;x=(f ? -x : x);
}
int head[maxn],nxt[maxn<<1],e[maxn<<1];
int mp_cnt;
void init_mp(){memset(head,-1,sizeof(head));mp_cnt=-1;
}
void add_edge(int u,int v){e[++mp_cnt]=v;nxt[mp_cnt]=head[u];head[u]=mp_cnt;
}
int t[maxn];
int n,l,r;
int vis[maxn],s[maxn];
int rt,rti,tot;
LL ans=0;
void bsort(vector<int>& v){//桶排int mx=0;for(int i=0;i<(int)v.size();i++){++t[v[i]];mx=max(mx,v[i]);}v.clear();for(int i=0;i<=mx;i++){while(t[i]){--t[i];v.push_back(i);}}
}
void get_rt(int u,int fa){//寻找子树重心int p=0;s[u]=1;for(int i=head[u];~i;i=nxt[i]){int v=e[i];if(v==fa||vis[v]) continue;get_rt(v,u);s[u]+=s[v];p=max(p,s[v]);}p=max(p,tot-s[u]);if(p<=rti) rt=u,rti=p;
}
vector<int> v1,v2;
void get_dis(int u,int fa,int d){//获取子树内所有距离v1.push_back(d),v2.push_back(d);for(int i=head[u];~i;i=nxt[i]){int v=e[i];if(v==fa||vis[v]) continue;get_dis(v,u,d+1);}
}
LL counter(vector<int>& v,int lim){//双指针LL p=0,sum=0;int r=(int)v.size()-1;for(int i=0;i<(int)v.size();i++) sum+=v[i];for(int i=0;i<(int)v.size();i++){sum-=v[i];while(r>=0&&v[i]+v[r]>lim) sum-=v[r--];if(r<i) break;p+=sum+1ll*(r-i)*v[i];}return p;
}
void work(int u){//计算答案v1.clear();v1.push_back(0);for(int i=head[u];~i;i=nxt[i]){int v=e[i];if(vis[v]) continue;v2.clear();get_dis(v,u,1);bsort(v2);ans-=counter(v2,r)-counter(v2,l-1);}bsort(v1);ans+=counter(v1,r)-counter(v1,l-1);
}
void dfs(int u){vis[u]=1,work(u);for(int i=head[u];~i;i=nxt[i]){int v=e[i];if(vis[v]) continue;rti=inf,tot=s[v];get_rt(v,u);dfs(rt);}
}
int main(){read(n),read(l),read(r);int u;init_mp();for(int i=2;i<=n;i++){read(u);add_edge(u,i),add_edge(i,u);}tot=n,rti=inf;get_rt(1,1);dfs(rt);printf("%lld",ans);return 0;
}
//^o^

你可能会发现在求重心时的子树大小并不是正确的,因为其根节点是不同的

但是这并不影响正确性与时间复杂度,详见这里

所以你会发现,这里不能使用 \(oi\;wiki\) 中这种方法来判断重心

由于使用了桶排,这段代码的时间复杂度为 \(O(n\;log\;n)\)

http://www.sczhlp.com/news/21765/

相关文章:

  • DeepSeek 模型本地部署安装教程(超级详细,附安装包) 2025最新版详细图文安装教程(超详细保姆级小白教程)
  • 银河麒麟V10 下源码编译安装 Redis 并注册为系统服务
  • 网站开发制作企业查询软件
  • app开发网站建设及开发营销方案ppt
  • wordpress菜单栏优化百度seo官网
  • 长沙建设网站的公司跨境网站建站
  • css 网站根目录宁波seo推广定制
  • 哪个网站做室内效果图厉害网站多少钱
  • 万户网络web工作流广州seo公司如何
  • 网站首页怎么做psseo网站优化培训
  • 做网站用的编程语言百度售后服务电话
  • 济南做设计公司网站广东今日最新疫情通报
  • Python 3.11安装教程(超级详细,附安装包) 2025最新版详细图文安装教程
  • 从零打造一个在线客服插件:我的踩坑与思考
  • 8.20模考总结
  • 实战GPU编程(python高性能计算)2:环境验证
  • 做网站开发钱百度网络营销app
  • 织梦贷款网站模板嘉兴网站建设制作
  • OSI七层网络模型
  • 【题解】P2893 Making the Grade G
  • Kubernetes核心组件
  • Helm+ArgoCD的持续部署方案
  • 网站做的不好会有什么后果长清区seo网络优化软件
  • web技术网站开发广州网站关键词排名
  • 做网站那几步网络运营是做什么的工作
  • 白城网站建设公司长沙营销型网站建设
  • 中国建设网网站建网站需要什么条件
  • 姑苏网站制作技能培训有哪些科目
  • 网页无法访问6网站优化排名查询
  • 支付宝手机网站支付百度空间登录