点分治小记
前言
点分治适合处理大规模的树上路径信息问题。
例题:Tree
假设我们要对根为
- 路径包含 rt 的。而这种路径可以看作
- 不包含 rt 的。
对于情况 1。设定
这样来看,一次统计是
但是时间复杂度并没有加快很多。此处引入树的重心,定义:对于一个无根树,指定
假如我们每次都取树的重心为新的根,那么新的树最多有
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+10;
struct EDGE{int v,nxt,w;}e[N*2];
int h[N],idx;
void ae(int x,int y,int w) {e[++idx] = {y,h[x],w};h[x] = idx;}
int n,ans,k;
struct BIT{
int c[N],t[N];
int tg,len=N;
void clear() {tg++;}
void init(int l) {len=l;}
#define lowbit(x) ((x)&-(x))
void upd(int x,int k) {for(;x<=len;x+=lowbit(x)) if(tg==t[x]) c[x]+=k; else c[x]=k, t[x]=tg;}
int s(int x) {int p=0;for(;x;x-=lowbit(x)) if(tg==t[x]) p+=c[x]; return p;}
}c;
int vis[N],root,rnum,sum;// 注意维护 root:重心,rnum:f_root sum:n
// 如果 vis_x == 1.那么认定该节点被删除。
int sz[N];
void GRoot(int u,int fa) { // 求根
/*
虽然树的重心在定义上来说,是以每一个点为根的。但是也可以指定一个为根。
第 i 个时候算出 i 的子树的值与子树的父亲的值。
*/
sz[u] = 1;
int ssz = 0;// son size
for(int i = h[u];i;i=e[i].nxt) {
int w = e[i].w, v = e[i].v;
if(v == fa || vis[v]) continue;
GRoot(v,u);
sz[u] += sz[v];
ssz = max(ssz ,sz[v]);
}
if(ssz < sum - sz[u]) ssz = sum - sz[u];
if(ssz < rnum) rnum = ssz, root = u;
}
int q[N], cnt;
void dfs(int u,int fa,int d) {
if(d<=k) q[++cnt] = d;
for(int i = h[u];i;i = e[i].nxt) {
int v = e[i].v, w = e[i].w;
if(v == fa || vis[v]) continue;
dfs(v,u,d+w);
}
}
void dfa(int u) {
vis[u] = 1;
c.upd(0 + 1,1);// 路径也可以形如 rt->B。不一定是 A->rt->B。
// + 1 是因为树状数组中 lowbit(0) = 0 而设置的偏移量。
for(int i = h[u];i;i = e[i].nxt) {
int v = e[i].v, w = e[i].w;
if(vis[v]) continue;
dfs(v,u,w);
for(int j=1;j<=cnt;j++) ans += c.s(k-q[j] + 1);
for(int j=1;j<=cnt;j++) c.upd(q[j] + 1,1);
cnt = 0;
}
c.clear(); // clear BIT
for(int i = h[u];i;i = e[i].nxt) {
int v = e[i].v;
if(vis[v]) continue;
sum = sz[v], rnum = 1e9;
GRoot(v,-1), GRoot(root,-1);
//这两行不要缺漏,多求一遍方便下一次求根时算 sum
dfa(root);
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>n;
for(int i=1;i<n;i++) {
int x,y,w;
cin>>x>>y>>w;
ae(x,y,w), ae(y,x,w);
}
cin>>k;
c.init(k);
sum = n; rnum = 1e9;
GRoot(1,-1), GRoot(root,-1);
dfa(root);
cout<<ans;
return 0;
}
本文作者:cjrqwq
本文链接:https://www.cnblogs.com/yfzqwq/p/18492758
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探