P3178 [HAOI2015] 树上操作
P3178 [HAOI2015] 树上操作
题目描述
有一棵点数为 \(N\) 的树,以点 \(1\) 为根,且树有点权。然后有 \(M\) 个操作,分为三种:
- 操作 \(1\):把某个节点 \(x\) 的点权增加 \(a\)。
- 操作 \(2\):把某个节点 \(x\) 为根的子树中所有点的点权都增加 \(a\)。
- 操作 \(3\):询问某个节点 \(x\) 到根的路径中所有点的点权和。
提示
对于 \(100\%\) 的数据,\(1\le N,M\le10^5\),且所有输入数据的绝对值都不会超过 \(10^6\)。
Solution:
十分有趣的 dfs 序+线段树。
我们思考一下贡献如何产生:我们用线段树维护每个点到根节点这条路径上的权值。
那么操作1就相当于在 \([st_x,ed_x]\) 上加上一个 \(a\).
对于操作2:我们考虑这个操作对其子树内一个点 \(y\) 的贡献:\((-dep_x+dep_y+1)\times a\) 我们将其拆开:\(-(dep_x-1)\times a \ + \ dep_y\times a\) 我们将前半段挂到 \(x\) 的子树下,后半段挂在 \(y\) 上。
实现:
我们维护一颗线段树,每个节点维护两类贡献\(val_0 ,val_1\) 分别表示对于这个点直接产生的贡献(操作1和操作二的前半部分)和与这个点的深度有关的贡献(操作2的后半部分)。
然后这题就做完了。
Code:
#include<bits/stdc++.h>
#define int long long
const int N=1e5+5;
using namespace std;
int n,m,tot;
int dep[N],st[N],ed[N],rid[N];
vector<int> E[N];
void dfs(int x,int fa)
{
st[x]=++tot;dep[x]=dep[fa]+1;
for(auto y : E[x])if(y!=fa)dfs(y,x);
ed[x]=tot;rid[st[x]]=x;
}
struct Segment_Tree{
struct Tree{
int tag[2],val[2];
}t[N<<2];
#define ls x<<1
#define rs x<<1|1
inline void add(int x,int k,int id){t[x].tag[id]+=k,t[x].val[id]+=k;}
inline void pushdown(int x)
{
if(t[x].tag[0]){add(ls,t[x].tag[0],0);add(rs,t[x].tag[0],0);t[x].tag[0]=0;}
if(t[x].tag[1]){add(ls,t[x].tag[1],1);add(rs,t[x].tag[1],1);t[x].tag[1]=0;}
}
void upd(int x,int l,int r,int L,int R,int k,int id)
{
if(L<=l&&r<=R){add(x,k,id);return;}
int mid=l+r>>1;pushdown(x);
if(L<=mid)upd(ls,l,mid,L,R,k,id);
if(mid<R)upd(rs,mid+1,r,L,R,k,id);
}
int query(int x,int l,int r,int pos)
{
if(l==r)return dep[rid[pos]]*t[x].val[0]+t[x].val[1];
int mid=l+r>>1;pushdown(x);
if(pos<=mid)return query(ls,l,mid,pos);
else return query(rs,mid+1,r,pos);
}
}T;
int a[N];
void work()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
for(int i=2,x,y;i<=n;i++)
{
scanf("%lld%lld",&x,&y);
E[x].push_back(y);E[y].push_back(x);
}
dfs(1,0);
for(int i=1;i<=n;i++)T.upd(1,1,n,st[i],ed[i],a[i],1);
for(int i=1,opt,x,y;i<=m;i++)
{
scanf("%lld%lld",&opt,&x);
if(opt==1)
{
scanf("%lld",&y);
T.upd(1,1,n,st[x],ed[x],y,1);
}
if(opt==2)
{
scanf("%lld",&y);
T.upd(1,1,n,st[x],ed[x],-y*(dep[x]-1),1);
T.upd(1,1,n,st[x],ed[x],y,0);
}
if(opt==3)
{
int ans=T.query(1,1,n,st[x]);
printf("%lld\n",ans);
}
}
}
#undef int
int main()
{
//freopen("P3178.in","r",stdin);freopen("P3178.out","w",stdout);
work();
return 0;
}

浙公网安备 33010602011771号