BZOJ4034 T2
Description
有一棵点数为\(N\)的树,以点\(1\)为根,且树点有边权。然后有\(M\)个操作,分为三种:
操作 1 :把某个节点\(x\)的点权增加\(a\)。
操作 2 :把某个节点\(x\)为根的子树中所有点的点权都增加\(a\)。
操作 3 :询问某个节点\(x\)到根的路径中所有点的点权和。
Input
第一行包含两个整数\(N, M\) 。表示点数和操作数。
接下来一行\(N\)个整数,表示树中节点的初始权值。
接下来\(N-1\)行每行三个正整数\(fr, to\), 表示该树中存在一条边\((fr, to)\)。
再接下来\(M\)行,每行分别表示一次操作。其中第一个数表示该操作的种类$ 1-3 $ ,之后接这个操作的参数\(x\)或者\(x,a\) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
Sample Output
6
9
13
HINT
对于\(100\%\)的数据,\(N,M \le 100000\),且所有输入数据的绝对值都不会超过\(10^{6}\)。
利用进栈出栈序列(dfs序),进栈权值为正,出栈为负,构建线段树。查询就是前缀和啦!!!
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
typedef long long ll;
#define maxn (200010)
ll n,m,L[maxn],R[maxn],side[maxn],next[maxn],toit[maxn],w[maxn],dfn[maxn],cnt,Ts,tag[maxn*4],zheng[maxn*4];
ll sum[maxn*4];
inline void add(ll a,ll b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; }
inline void ins(ll a,ll b) { add(a,b); add(b,a); }
inline void dfs(ll now,ll fa)
{
dfn[++Ts] = now; L[now] = Ts;
for (ll i = side[now];i;i = next[i]) { if (toit[i] == fa) continue; dfs(toit[i],now); }
dfn[++Ts] = -now; R[now] = Ts;
}
inline void build(ll l,ll r,ll now)
{
if (l == r) { zheng[now] = dfn[l] > 0; sum[now] = (dfn[l] > 0?1:-1)*w[abs(dfn[l])]; return; }
ll mid = (l + r)>>1;
build(l,mid,now<<1); build(mid+1,r,now<<1|1);
sum[now] = sum[now<<1]+sum[now<<1|1];
zheng[now] = zheng[now<<1]+zheng[now<<1|1];
}
inline void pushdown(ll now,ll l,ll r)
{
if (!tag[now]) return;
if (l != r)
{
ll mid = (l+r)>>1;
sum[now<<1] += zheng[now<<1]*tag[now];
sum[now<<1|1] += zheng[now<<1|1]*tag[now];
sum[now<<1] -= (mid-l+1-zheng[now<<1])*tag[now];
sum[now<<1|1] -= (r-mid-zheng[now<<1|1])*tag[now];
tag[now<<1] += tag[now]; tag[now<<1|1] += tag[now];
}
tag[now] = 0;
}
inline void modify(ll ql,ll qr,ll key,ll l,ll r,ll now)
{
pushdown(now,l,r);
if (ql <= l&&r <= qr)
{
sum[now] += zheng[now]*key;
sum[now] -= (r-l+1-zheng[now])*key;
tag[now] += key; return;
}
ll mid = (l + r) >> 1;
if (qr <= mid) modify(ql,qr,key,l,mid,now<<1);
else if (ql > mid) modify(ql,qr,key,mid+1,r,now<<1|1);
else modify(ql,mid,key,l,mid,now<<1),modify(mid+1,qr,key,mid+1,r,now<<1|1);
sum[now] = sum[now<<1]+sum[now<<1|1];
}
inline ll query(ll ql,ll qr,ll l,ll r,ll now)
{
pushdown(now,l,r);
if (ql <= l&&r <= qr) return sum[now];
ll mid = (l + r) >> 1;
if (qr <= mid) return query(ql,qr,l,mid,now<<1);
else if (ql > mid) return query(ql,qr,mid+1,r,now<<1|1);
else return query(ql,mid,l,mid,now<<1)+query(mid+1,qr,mid+1,r,now<<1|1);
}
int main()
{
freopen("4034.in","r",stdin);
freopen("4034.out","w",stdout);
scanf("%lld %lld",&n,&m);
for (ll i = 1;i <= n;++i) scanf("%lld",w+i);
for (ll i = 1,a,b;i < n;++i) scanf("%lld %lld",&a,&b),ins(a,b);
dfs(1,0); build(1,n<<1,1);
while (m--)
{
ll opt; scanf("%lld",&opt);
if (opt == 1)
{
ll x,a; scanf("%lld %lld",&x,&a);
modify(L[x],L[x],a,1,n<<1,1);
modify(R[x],R[x],a,1,n<<1,1);
}
else if (opt == 2)
{
ll x,a; scanf("%lld %lld",&x,&a);
modify(L[x],R[x],a,1,n<<1,1);
}
else
{
ll x; scanf("%lld",&x);
printf("%lld\n",query(1,R[x]-1,1,n<<1,1));
}
}
fclose(stdin); fclose(stdout);
return 0;
}
高考结束,重新回归。