尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

点分树

点分树
📅 发布时间:2026/6/19 18:19:39

事实上比较朴素。

P6329 【模板】点分树 | 震波

大致思路是将点分治的那个过程建成一棵树。每一层的重心和下一层的中心连边。

这棵树有两个重要性质:树高保证为 \(\log n\),任意两点的 lca 一定在这两个点的路径上。

于是我们可以在这棵树上做一些类似于 DP 的事情去统计路径的问题。由于保证了树高,因此我们可以有一些很暴力的操作,比如跳根链和暴力存子树内的每一个点之类的。

对于原题,我们先建出点分树,然后对每一个点开一个动态开点线段树维护点分树上子树内的所有点到当前点距离的权值。
例如说,我们对于询问距离 \(u\) 小于等于 \(x\) 的节点的权值和,我们就去枚举 \(v\) 表示 \(u\) 到点分树上根链的所有点。

于是就是询问 \(v\) 子树中到 \(u\) 距离不超过 \(x-dis(v,u)\) 的点的个数,这个过程相当于将 \(v\) 当作 lca 然后统计经过这个 lca 的点对的贡献。但是注意如果 \(v\) 是 lca 那么另一个点不能在 \(u\) 所在的那个子树中,因此要去掉在 \(u\) 那个方向的子树的贡献。我们再开一颗线段树将这个东西挂在对应方向的那个子树上,也就是每个点维护子树内每个点到父亲的距离的权值。
然后查询和修改的时候就暴力跳根链改对应线段树即可。

code

注意到需要求两点间距离,因此需要调用巨量次 lca,因此建议写一个 \(O(1)\) 查询的东西。普通的树上倍增太慢了。

自认为比较好看。

点击查看代码
#include<bits/stdc++.h>
bool Mbe;
using namespace std;
#define ll long long
//namespace FIO{
//	template<typename P>
//	inline void read(P &x){P res=0,f=1;char ch=getchar();while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}x=res*f;}
//	template<typename Ty,typename ...Args>
//	inline void read(Ty &x,Args &...args) {read(x);read(args...);}
//	inline void write(ll x) {if(x<0ll)putchar('-'),x=-x;static int sta[35];int top = 0;do {sta[top++] = x % 10ll, x /= 10ll;} while (x);while (top) putchar(sta[--top] + 48);}
//}
//using FIO::read;using FIO::write;
const int N=1e5+7;
int n,m,val[N],zx,siz[N],mxsiz[N],vis[N],F[N];
vector<int> q[N],p[N];
void Max(int &x,const int &y){x=max(x,y);}
void Min(int &x,const int &y){x=min(x,y);}
namespace LCA{int dfncnt=0,dfn[N],loc[N],f[N][17],Lg[N],dep[N];void dfs(int u,int fa){dfn[u]=++dfncnt,loc[dfn[u]]=u;f[dfn[u]][0]=dfn[fa];dep[u]=dep[fa]+1;for(int i=1;(1<<i)+1<=dfn[u];i++)f[dfn[u]][i]=min(f[dfn[u]][i-1],f[dfn[u]-(1<<(i-1))][i-1]);for(int v:q[u]){if(v==fa)continue;dfs(v,u);}}void init(){Lg[0]=-1;for(int i=1;i<=n;i++)Lg[i]=Lg[i/2]+1;dfs(1,0);}int get(int l,int r){int k=Lg[r-l+1];return min(f[r][k],f[l+(1<<k)-1][k]);}int lca(int x,int y){if(x==y)return x;if(dfn[x]>dfn[y])swap(x,y);return loc[get(dfn[x]+1,dfn[y])];}int getdis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
}
using LCA::getdis;using LCA::lca;
void findrt(int u,int fa,int sumsiz){siz[u]=1;mxsiz[u]=0;for(int v:q[u]){if(v==fa||vis[v])continue;findrt(v,u,sumsiz);Max(mxsiz[u],siz[v]);siz[u]+=siz[v];}Max(mxsiz[u],sumsiz-siz[u]);if(mxsiz[u]<mxsiz[zx])zx=u;
}
void build_tr(int u,int fa){if(fa)p[fa].push_back(u),p[u].push_back(fa);vis[u]=1;for(int v:q[u]){if(vis[v])continue;mxsiz[0]=n,zx=0;findrt(v,u,siz[v]);build_tr(zx,u);}
}
struct sgt{int idcnt=0,rt[N],tr[N<<6],ls[N<<6],rs[N<<6];#define mid ((l+r)>>1)void push_up(int u){tr[u]=tr[ls[u]]+tr[rs[u]];}void modify(int &u,int l,int r,int x,int w){if(!u)u=++idcnt;if(l==r){tr[u]+=w;return;}x<=mid?modify(ls[u],l,mid,x,w):modify(rs[u],mid+1,r,x,w);push_up(u);}int query(int u,int l,int r,int ql,int qr){if(!u)return 0;if(ql<=l&&r<=qr)return tr[u];int res=0;if(ql<=mid)res+=query(ls[u],l,mid,ql,qr);if(qr>mid)res+=query(rs[u],mid+1,r,ql,qr);return res;}
}t1,t2;
vector<int>id[N];
void dfs(int u,int fa){id[u].push_back(u);F[u]=fa;for(int v:p[u]){if(v==fa)continue;dfs(v,u);for(int w:id[v])id[u].push_back(w);}for(int v:id[u]){t1.modify(t1.rt[u],0,n,getdis(u,v),val[v]);if(fa)t2.modify(t2.rt[u],0,n,getdis(fa,v),val[v]);}
}
bool Med;
signed main(){  //注意 vis!!!ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);//freopen(".in","r",stdin);//freopen(".out","w",stdout);cin>>n>>m;for(int i=1;i<=n;i++)cin>>val[i];for(int i=1,u,v;i<n;i++)cin>>u>>v,q[u].push_back(v),q[v].push_back(u);LCA::init();mxsiz[0]=n,zx=0;findrt(1,0,n);int RT=zx;  //这个是点分树的真正的根build_tr(zx,0);dfs(RT,0);int lst=0;for(int i=1;i<=m;i++){int op,u,x;cin>>op>>u>>x;u^=lst,x^=lst;if(op==0){int ans=t1.query(t1.rt[u],0,n,0,x),bu=u;while(F[u]){if(getdis(F[u],bu)<=x)ans+=t1.query(t1.rt[F[u]],0,n,0,x-getdis(bu,F[u]))-t2.query(t2.rt[u],0,n,0,x-getdis(bu,F[u]));u=F[u];}cout<<ans<<'\n';lst=ans;}else{int bu=u;while(u){t1.modify(t1.rt[u],0,n,getdis(u,bu),x-val[bu]);if(F[u])t2.modify(t2.rt[u],0,n,getdis(F[u],bu),x-val[bu]);u=F[u];}val[bu]=x;}}cerr<<'\n'<<1e3*clock()/CLOCKS_PER_SEC<<"ms\n";cerr<<'\n'<<fabs(&Med-&Mbe)/1048576.0<<"MB\n";return 0;
}

相关新闻

  • HTTP请求走私漏洞介绍 - 实践
  • 深入解析:Spring MVC 拦截器interceptor
  • 《重生之我成为世界顶级黑客》第八章:未来野望

最新新闻

  • 上海汽车音响改装选哪家?上海音乐人生,二十年赛事级连锁标杆门店 - 音乐人生汽车音响
  • 技术解析:从Tri-Plane到3D GAN,如何实现高效且一致的神经渲染
  • 通过Selenium实现网页截图来生成应用封面
  • 2026苏州钻石回收实测|国标4C定级,全城无套路靠谱门店变现指南 - 薛定谔的梨花猫
  • C语言宽字符处理:wmemcmp、wmemcpy、wprintf核心函数详解与实战
  • 多模态大语言模型LISA

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号