列表

详情


NC19995. [HAOI2015]树上操作

描述

有一棵点数为 N 的树,以点 1 为根,且树点有边权。
然后有 M 个 操作,分为三种: 
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

输入描述

第一行包含两个整数N, M。表示点数和操作数。
接下来一行N个整数,表示树中节点的初始权值。
接下来N-1行每行三个正整数 fr, to ,表示该树中存在一条边 (fr, to) 。
再接下来M行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ),之后接这个操作的参数( x 或者 x a ) 。

输出描述

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

示例1

输入:

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

输出:

6
9
13

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 210ms, 内存消耗: 12924K, 提交时间: 2019-06-01 22:38:15

#include <cstdio>
#include <cstring>
#define LL long long
#define root 1, 1, n
#define ls now << 1, l, mid
#define rs now << 1 | 1, mid + 1, r
using namespace std;
const int MAXN = 100001;
int n, m, cnt, tot;
int head[MAXN], next[MAXN << 1], to[MAXN << 1], tid[MAXN], size[MAXN];
LL a[MAXN << 2], b[MAXN << 2], val[MAXN], dis[MAXN];
inline void add(int x, int y)
{
	to[cnt] = y;
	next[cnt] = head[x];
	head[x] = cnt++;
}
inline void dfs(int u)
{
	int i, v;
	tid[u] = ++tot;
	size[u] = 1;
	for (i = head[u]; i != -1; i = next[i])
	{
		v = to[i];
		if (!size[v])
		{
			dis[v] = dis[u] + 1;
			dfs(v);
			size[u] += size[v];
		}
	}
}
inline void push_down(int now)
{
	a[now << 1] += a[now];
	a[now << 1 | 1] += a[now];
	b[now << 1] += b[now];
	b[now << 1 | 1] += b[now];
	a[now] = b[now] = 0;
}
inline void update(LL x, LL y, int ql, int qr, int now, int l, int r)
{
	if (ql <= l && r <= qr)
	{
		a[now] += x;
		b[now] += y;
		return;
	}
	push_down(now);
	int mid = (l + r) >> 1;
	if (ql <= mid) update(x, y, ql, qr, ls);
	if (mid < qr) update(x, y, ql, qr, rs);
}
inline LL query(int u, int x, int now, int l, int r)
{
	if (l == r) return dis[u] * a[now] + b[now];
	push_down(now);
	int mid = (l + r) >> 1;
	if (x <= mid) return query(u, x, ls);
	else return query(u, x, rs);
}
int main()
{
	int i, x, z;
	int y;
	scanf("%d %d", &n, &m);
	for (i = 1; i <= n; i++)    scanf("%lld", &val[i]);
	memset(head, -1, sizeof(head));
	for (i = 1; i < n; i++)
	{
		scanf("%d %d", &x, &y);
		add(x, y);
		add(y, x);
	}
	dis[1] = 1;
	dfs(1);
	for (i = 1; i <= n; i++) update(0, val[i], tid[i], tid[i] + size[i] - 1, root);
	for (i = 1; i <= m; i++)
	{
		scanf("%d %d", &z, &x);
		if (z == 1)
		{
			scanf("%d", &y);
			update(0, y, tid[x], tid[x] + size[x] - 1, root);
		}
		else if (z == 2)
		{
			scanf("%d", &y);
			update(y, -((dis[x] - 1) * y), tid[x], tid[x] + size[x] - 1, root);
		}
		else printf("%lld\n", query(x, tid[x], root));
	}
	return 0;
}

C++(clang++11) 解法, 执行用时: 206ms, 内存消耗: 15092K, 提交时间: 2021-03-30 17:34:43

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<string>
#include<queue>
#include<vector>
#define ll long long

using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 100005;

int N,M;
int a[maxn],fa[maxn]; 
vector<int>G[maxn];
int L[maxn],R[maxn],cnt = 0;
ll c[maxn][2],deep[maxn];
void dfs(int u,int pre)
{
    L[u] = ++cnt;
    deep[u] = deep[pre]+1;
    for(int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        if(v == pre) continue;
        dfs(v,u);
    }
    R[u] = cnt;
}

int lowbit(int x)
{
    return x&(-x);
}
void update(int x,ll v,int y)
{
    while(x <= N)
    {
        c[x][y]+=v;
        x+=lowbit(x);
    }
}
ll getsum(int x,int y)
{
    ll sum = 0;
    while(x>=1)
    {
        sum+=c[x][y];
        x-=lowbit(x);
    }
    return sum;
}
int main()
{
    cin>>N>>M;
    for(int i = 1; i<= N; i++) cin>>a[i];
    for(int i = 1; i <= N-1; i++)
    {
        int u,v;
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1,0);
    for(int i = 1; i<= N; i++)
    {
        update(L[i],a[i],0);
        update(R[i]+1,-a[i],0);
    }
    while(M--)
    {
        int q,x,a;
        cin>>q>>x;
        if(q == 1)
        {
            cin>>a;
            update(L[x],a,0);
            update(R[x]+1,-a,0);
        }
        else if(q == 2)
        {
            cin>>a;
            update(L[x],-(deep[x]-1)*a,0);
            update(R[x]+1,(deep[x]-1)*a,0);
            
            update(L[x],a,1);
            update(R[x]+1,-a,1);
        }
        else if(q == 3)
        {
            ll ans = getsum(L[x],0) + deep[x]*getsum(L[x],1);
            cout<<ans<<endl;
        }
    }
    return 0;
}

上一题