题目
传送门
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和
题解
模板题
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
const ll maxn=1000005;
ll n,m,x,y,a[maxn],sum[maxn<<2],add[maxn<<2];
struct Edge{
ll next,to;
}edge[maxn<<1];
ll num_edge,head[maxn];
ll dfn[maxn],idfn[maxn],fa[maxn],top[maxn],deep[maxn],tot[maxn],son[maxn];
void add_edge(ll from,ll to)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
void dfs1(ll x,ll father,ll depth)
{
fa[x]=father;
deep[x]=depth;
tot[x]=1;
ll maxnow=-1;
for (ll i=head[x]; i!=0; i=edge[i].next)
{
ll to=edge[i].to;
if (to!=father)
{
dfs1(to,x,depth+1);
tot[x]+=tot[to];
if (tot[to]>maxnow)//写成了tot【now】!
{
maxnow=tot[to];//这里是找儿子而不是找x
son[x]=to;
}
}
}
}
ll cnt;//标记dfs序的计数器
void dfs2(ll x,ll tp)
{
top[x]=tp;
dfn[x]=++cnt;
idfn[cnt]=x;
if (!son[x]) return;
dfs2(son[x],tp);
for (ll i=head[x]; i!=0; i=edge[i].next)
{
ll to=edge[i].to;
if (to!=fa[x] && to!=son[x])
dfs2(to,to);
}
}
void pushup(ll rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(ll rt,ll ln,ll rn)
{
if (add[rt])
{
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
sum[rt<<1]+=add[rt]*ln;
sum[rt<<1|1]+=add[rt]*rn;
add[rt]=0;
}
}
void build_tree(ll l,ll r,ll rt)
{
if (l==r)
{
sum[rt]=a[idfn[l]]; return;
}
ll mid=(l+r)>>1;
build_tree(l,mid,rt<<1);
build_tree(mid+1,r,rt<<1|1);
pushup(rt);
}
void change_qujian(ll L,ll R,ll C,ll l,ll r,ll rt)
{
if (L<=l && r<=R)
{
add[rt]+=C; sum[rt]+=(r-l+1)*C; return;
}
ll mid=(l+r)>>1;
pushdown(rt,mid-l+1,r-mid);
if (L<=mid) change_qujian(L,R,C,l,mid,rt<<1);
if (R>mid) change_qujian(L,R,C,mid+1,r,rt<<1|1);
pushup(rt);
}
ll ques_sum(ll L,ll R,ll l,ll r,ll rt)
{
if (L<=l && r<=R)
return sum[rt];
ll mid=(l+r)>>1;
pushdown(rt,mid-l+1,r-mid);
ll ans=0;
if (L<=mid) ans+=ques_sum(L,R,l,mid,rt<<1);
if (R>mid) ans+=ques_sum(L,R,mid+1,r,rt<<1|1);
pushup(rt);//忘记了pushup!!!
return ans;
}
ll ques_tree_sum(ll x,ll y)
{
ll ans=0;
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
ans+=ques_sum(dfn[top[x]],dfn[x],1,n,1);
x=fa[top[x]];//向上跳
}
if (deep[x]>deep[y])
swap(x,y);
ans+=ques_sum(dfn[x],dfn[y],1,n,1);
return ans;
}
int main()
{
memset(deep,-1,sizeof(deep));
scanf("%lld",&n); scanf("%lld",&m);
for (ll i=1; i<=n; i++) scanf("%lld",&a[i]);
for (ll i=1; i<=n-1; i++)
{
scanf("%lld%lld",&x,&y);
add_edge(x,y); add_edge(y,x);
}
dfs1(1,1,1);
dfs2(1,1);
build_tree(1,n,1);
for (ll i=1; i<=m; i++)
{
ll opt;
scanf("%lld",&opt);
if (opt==1)
{
scanf("%lld%lld",&x,&y);
change_qujian(dfn[x],dfn[x],y,1,n,1);
}
if (opt==2)
{
scanf("%lld%lld",&x,&y);
change_qujian(dfn[x],dfn[x]+tot[x]-1,y,1,n,1);
}
if (opt==3)
{
scanf("%lld",&x);
printf("%lld\n",ques_tree_sum(x,1));
}
}
return 0;
}
总结
那万恶的long long!
if (L<=l && r<=R)
{
add[rt]+=C; sum[rt]+=(r-l+1)*C; return;
}
pushup中:
sum[rt<<1]+=add[rt]*ln;
sum[rt<<1|1]+=add[rt]*rn;
浪费了我下午两个小时的时间!
我还是太菜了!!
赶紧学莫队!