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;
}
高考结束,重新回归。
posted @ 2016-09-12 22:36  lmxyy  阅读(91)  评论(0编辑  收藏  举报