树上行走(牛客挑战赛57)
题目大意
给一棵个点的树,每个点都有一个初始的权值,有一个计数器,初始值为,现有两种操作:给定,令的最短路上的点构成的序列为,,增加;给定,输出的值。
思路
很容易想到树链剖分,但是新手如我,之后就不会了。不过幸好,大佬给了一点思路。首先我们当然不可能暴力的去更新每一个点的值,那么我们可以发现能对一个点产生贡献的无非是它的父亲、重儿子和轻儿子,然后我们发现每个点的父亲和重儿子都最多只有一个,轻儿子可以有很多但是一棵树种轻儿子的数量一定是很少的,所以我们就可以通过暴力更新轻儿子的贡献,而对于父亲和重儿子的贡献我们可以通过建两个数组的方法来进行标记,询问的时候一起加上就可以了。而快速标记的方法无非线段树和树状数组,这两种方法都可以。
树状数组代码
#include<bits/stdc++.h> using namespace std; int n,q; vector<vector<int>>v(500005); long long a[500005]; int dep[500005],siz[500005],son[500005],fa[500005]; int id[500005],top[500005],tot=0; long long ans[500005]; int tree[2][500005]; inline int read() { int s=0,w=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1; for (;ch>='0'&&ch<='9';ch=getchar())s=(s<<1)+(s<<3)+(ch^48); return (w==-1?-s:s); } void dfs(int x,int pre){ siz[x]=1; dep[x]=dep[pre]+1; fa[x]=pre; for(auto to:v[x])if(to!=pre){ dfs(to,x); siz[x]+=siz[to]; if(siz[to]>siz[son[x]])son[x]=to; } } inline void dfs1(int x,int father) { id[x]=++tot; if(son[x]) { top[son[x]]=top[x]; dfs1(son[x],x); } for(auto it:v[x])if(it!=father&&it!=son[x]) { top[it]=it; dfs1(it,x); } } inline int lca(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); x=fa[top[x]]; } if(dep[x]<dep[y])return x; else return y; } inline void update(int x,int w,int op) { while(x<=500005) { tree[op][x]+=w; x+=(x&-x); } } inline int query(int x,int op) { int sum=0; while(x) { sum+=tree[op][x]; x-=(x&-x); } return sum; } inline void Update1(int x,int y) { while(top[x]!=top[y]) { if(top[x]!=x) { update(id[top[x]],1,0); update(id[fa[x]]+1,-1,0); } x=top[x]; ans[fa[x]]+=a[x]; x=fa[x]; } if(x!=y) { update(id[y],1,0); update(id[fa[x]]+1,-1,0); } } inline void Update2(int x,int y) { while(top[x]!=top[y]) { update(id[top[y]],1,1); update(id[y]+1,-1,1); y=fa[top[y]]; } update(id[x]+1,1,1); update(id[y]+1,-1,1); } int main() { n=read(),q=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<n;i++) { int from=read(),to=read(); v[from].push_back(to); v[to].push_back(from); } dfs(1,0); top[1]=1; dfs1(1,0); while(q--) { int op=read(); if(op==1) { int x=read(),y=read(); int Lca=lca(x,y); if(x!=Lca)Update1(x,Lca); if(y!=Lca)Update2(Lca,y); } else { int x=read(); long long ans1=ans[x]; if(son[x])ans1+=a[son[x]]*query(id[x],0); if(fa[x])ans1+=a[fa[x]]*query(id[x],1); printf("%lld\n",ans1); } } return 0; }
线段树代码
#include<bits/stdc++.h> using namespace std; int n,q; vector<vector<int>>v(500005); long long a[500005]; int dep[500005],siz[500005],son[500005],fa[500005]; int id[500005],top[500005],tot=0; long long ans[500005]; int laz[3][2000005]; inline int read() { int s=0,w=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1; for (;ch>='0'&&ch<='9';ch=getchar())s=(s<<1)+(s<<3)+(ch^48); return (w==-1?-s:s); } inline void dfs(int x,int father) { siz[x]=1; dep[x]=dep[father]+1; int maxsize=0; for(auto it:v[x])if(it!=father) { fa[it]=x; dfs(it,x); siz[x]+=siz[it]; if(siz[it]>maxsize) { maxsize=siz[it]; son[x]=it; } } } inline void dfs1(int x,int father) { id[x]=++tot; if(son[x]) { top[son[x]]=top[x]; dfs1(son[x],x); } for(auto it:v[x])if(it!=father&&it!=son[x]) { top[it]=it; dfs1(it,x); } } inline int lca(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]])swap(x,y); x=fa[top[x]]; } if(dep[x]<dep[y])return x; else return y; } inline void update(int p,int l,int r,int w,int x,int y,int op) { if(x<=l&&r<=y) { laz[op][p]+=w; return; } int mid=(l+r)>>1; if(x<=mid)update(p<<1,l,mid,w,x,y,op); if(mid<y)update(p<<1|1,mid+1,r,w,x,y,op); } inline void Update1(int x,int y) { while(top[x]!=top[y]) { if(top[x]!=x) { update(1,1,n,1,id[top[x]],id[fa[x]],1); } x=top[x]; ans[fa[x]]+=a[x]; x=fa[x]; } if(x!=y) { update(1,1,n,1,id[y],id[fa[x]],1); } } inline void Update2(int x,int y) { while(top[x]!=top[y]) { update(1,1,n,1,id[top[y]],id[y],2); y=fa[top[y]]; } update(1,1,n,1,id[x]+1,id[y],2); } inline long long Query(int p,int l,int r,int x,int y,int cnt1,int cnt2) { if(l==r) { cnt1+=laz[1][p],cnt2+=laz[2][p]; return ans[y]+a[son[y]]*cnt1+a[fa[y]]*cnt2; } int mid=(l+r)>>1; if(x<=mid)return Query(p<<1,l,mid,x,y,cnt1+laz[1][p],cnt2+laz[2][p]); else return Query(p<<1|1,mid+1,r,x,y,cnt1+laz[1][p],cnt2+laz[2][p]); } int main() { n=read();q=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<n;i++) { int from=read(),to=read(); v[from].push_back(to); v[to].push_back(from); } dfs(1,0); top[1]=1; dfs1(1,0); while(q--) { int op=read(); if(op==1) { int x=read(),y=read(); int Lca=lca(x,y); if(x!=Lca)Update1(x,Lca); if(y!=Lca)Update2(Lca,y); } else { int x=read(); printf("%lld\n",Query(1,1,n,id[x],x,0,0)); } } return 0; }
__EOF__

本文作者:Jerry-Black
本文链接:https://www.cnblogs.com/Jerry-Black/p/15921374.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
本文链接:https://www.cnblogs.com/Jerry-Black/p/15921374.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)