NC232621. 树上行走
描述
输入描述
第一行两个正整数 。之后一行 个数,第 个数为 。
之后 行,每行两个正整数 ,表示树上存在一条 之间的边。
之后 行,每行形如 或 表示一次操作或询问。
输出描述
对于所有询问,输出一行一个数表示答案。
示例1
输入:
6 8 1 10 100 1000 10000 100000 1 2 1 3 2 4 2 5 3 6 1 4 6 1 6 5 2 1 2 2 2 3 2 4 2 5 2 6
输出:
110 1001 100001 0 10 100
C++ 解法, 执行用时: 858ms, 内存消耗: 66832K, 提交时间: 2022-03-07 17:00:19
#include<bits/stdc++.h> #define LL long long #define pb push_back using namespace std; const int N=5e5+9; int n,q,cnt; int a[N],c[N][2],d[N],son[N],tp[N],f[N],dfn[N],sz[N]; LL ans[N]; vector<int>e[N]; void dfs1(int x,int fa,int deep) { d[x]=deep; f[x]=fa; sz[x]=1; int maxn=0; for(int y:e[x]) { if(y==fa) continue; dfs1(y,x,deep+1); sz[x]+=sz[y]; if(sz[y]>maxn) maxn=sz[y],son[x]=y; } } void dfs2(int x,int top) { dfn[x]=++cnt; tp[x]=top; if(!son[x]) return; dfs2(son[x],top); for(int y:e[x]) if(y!=f[x]&&y!=son[x]) dfs2(y,y); } int lowbit(int x) { return x&-x; } void Add(int x,int t,int v) { while(x<=n) { c[x][t]+=v; x+=lowbit(x); } } void update(int x,int y) { while(tp[x]!=tp[y]) { if(d[tp[x]]>d[tp[y]]) { Add(dfn[tp[x]],0,1); Add(dfn[x],0,-1); ans[f[tp[x]]]+=a[tp[x]]; x=f[tp[x]]; } else { Add(dfn[tp[y]],1,1); Add(dfn[y]+1,1,-1); y=f[tp[y]]; } } if(d[x]>d[y]) { Add(dfn[y],0,1); Add(dfn[x],0,-1); } else { Add(dfn[x]+1,1,1); Add(dfn[y]+1,1,-1); } } int Sum(int x,int t) { int temp=0; while(x) { temp+=c[x][t]; x-=lowbit(x); } return temp; } int main() { ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1,x,y;i<n;i++) { cin>>x>>y; e[x].pb(y); e[y].pb(x); } dfs1(1,0,1); dfs2(1,1); while(q--) { int t,x,y; cin>>t; if(t==1) { cin>>x>>y; update(x,y); } else { cin>>x; cout<<ans[x]+1ll*a[son[x]]*Sum(dfn[x],0)+1ll*a[f[x]]*Sum(dfn[x],1)<<"\n"; } } return 0; }