P6329-[模板]点分树 | 震波

1|0正题

题目链接:https://www.luogu.com.cn/problem/P6329


1|1解题思路

给出n个点的一棵树,每个点有权值,有m次操作

  1. 修改一个点x的权值为y
  2. 询问距离点x不超过k的所有点点权和

1|2解题思路

点分树的模板题,先点分治构造出点分树,然后在上面维护信息。

对于每个点维护一个点分子树内,与该点的距离为下标,点权为权值的的树状数组,然后查询的时候直接查距离不超过kdis(now,x)的就好了。

发现与点分父节点会有算重的情况,这个时候顺便维护一个以与父节点的距离为下标的树状数组,然后减去重复的答案就好了。

时间复杂度O(nlog2n)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #define lowbit(x) (x&-x) using namespace std; const int N=1e5+10,T=18,inf=1e9; struct node{ int to,next; }a[N<<1]; int n,m,tot,cnt,num,root,fr,val[N]; int ls[N],f[N<<1][T],rfn[N],dep[N]; int fa[N],siz[N],lg[N<<1],mx; bool v[N]; struct BIT{ vector<int> t;int n; void Init(int x) {x++;t.resize(x);n=x;return;} void Change(int x,int val){ x++; while(x<=n){ t[x-1]+=val; x+=lowbit(x); } return; } int Ask(int x){ if(x<0)return 0; int ans=0;x++; if(x>n)x=n; while(x){ ans+=t[x-1]; x-=lowbit(x); } return ans; } }s1[N],s2[N]; void addl(int x,int y){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;return; } void dfs(int x,int fa){ dep[x]=dep[fa]+1; f[++cnt][0]=x;rfn[x]=cnt; for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(y==fa)continue; dfs(y,x);f[++cnt][0]=x; } return; } void groot(int x,int fa){ siz[x]=1;int f=0; for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(v[y]||y==fa)continue; groot(y,x);siz[x]+=siz[y]; f=max(f,siz[y]); } f=max(f,num-siz[x]); if(f<fr)root=x,fr=f; return; } void calc(int x,int fa,int dep){ mx=max(mx,dep); for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(y==fa||v[y])continue; calc(y,x,dep+1); } return; } void Build(int x,int h){ v[x]=1;int S=num,z=fr; mx=0;calc(x,x,0); s1[x].Init(mx); s2[x].Init(h); for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(v[y])continue; num=(siz[y]>siz[x])?(S-siz[x]):siz[y]; mx=0;calc(y,x,1); fr=inf;groot(y,x);y=root;fa[y]=x; Build(y,mx); } return; } void Init(){ dfs(1,1); for(int i=2;i<=cnt;i++)lg[i]=lg[i>>1]+1; for(int j=1;(1<<j)<=cnt;j++) for(int i=1;i+(1<<j)-1<=cnt;i++){ int x=f[i][j-1],y=f[i+(1<<j-1)][j-1]; f[i][j]=(dep[x]<dep[y])?x:y; } fr=inf;num=n;groot(1,1); Build(root,0); return; } int LCA(int l,int r){ l=rfn[l];r=rfn[r]; if(l>r)swap(l,r); int z=lg[r-l+1]; int x=f[l][z],y=f[r-(1<<z)+1][z]; return (dep[x]<dep[y])?x:y; } int dis(int x,int y) {return dep[x]+dep[y]-2*dep[LCA(x,y)];} void Updata(int x,int val){ int now=x; while(now){ s1[now].Change(dis(now,x),val); if(fa[now])s2[now].Change(dis(fa[now],x),val); now=fa[now]; } return; } int Ask(int x,int k){ int ans=0,now=x; ans=s1[x].Ask(k); while(fa[now]){ int d=dis(fa[now],x); ans+=s1[fa[now]].Ask(k-d); if(fa[now])ans-=s2[now].Ask(k-d); now=fa[now]; } return ans; } int main() { // freopen("P6329_1.in","r",stdin); // freopen("data.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&val[i]); for(int i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); addl(x,y);addl(y,x); } Init(); for(int i=1;i<=n;i++) Updata(i,val[i]); int last=0; while(m--){ int op,x,y; scanf("%d%d%d",&op,&x,&y); x^=last;y^=last; if(op){ Updata(x,y-val[x]); val[x]=y; } else printf("%d\n",last=Ask(x,y)); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/14301707.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(82)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示