牛客小白月赛9: D. 树上求和(dfs序+线段树)

链接:https://ac.nowcoder.com/acm/contest/275/D
来源:牛客网
 

题目描述

给你一棵根为1的有N个节点的树,以及Q次操作。
每次操作诸如:
1 x y:将节点x所在的子树的所有节点的权值加上y
2 x:询问x所在子树的所有节点的权值的平方和,答案模23333后输出

输入描述:

第一行两个整数N,Q
第二行N个整数,第i个表示节点i的初始权值
接下来N-1行每行两个整数u,v,表示u和v之间存在一条树边
接下来Q行每行一个操作,格式如题目描述

输出描述:

对于每个询问操作,输出一行一个整数,表示答案在模23333后的结果

输入

5 5
0 0 0 0 0
1 2
1 3
3 4
3 5
1 1 3
1 3 7
1 4 5
1 5 6
2 1

输出

599

 

两个模板往上拍就好

我这个还额外支持区间乘操作

 

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 23333
int cnt, a[100005], b[100005], in[100005], out[100005];
vector<int> G[100005];
typedef struct Tree
{
	LL x;
	LL X;
}Tree;
Tree tre[500005], lazy[500005];
void Create(int l, int r, int x)
{
	int m;
	lazy[x].X = 1;
	if(l==r)
	{
		tre[x].x = b[l]%mod;
		tre[x].X = (tre[x].x*tre[x].x)%mod;
		return;
	}
	m = (l+r)/2;
	Create(l, m, x*2);
	Create(m+1, r, x*2+1);
	tre[x].x = (tre[x*2].x+tre[x*2+1].x)%mod;
	tre[x].X = (tre[x*2].X+tre[x*2+1].X)%mod;
}
void GaoX(int l, int r, int x, LL val)
{
	tre[x].x = tre[x].x*val%mod;
	tre[x].X = tre[x].X*val%mod*val%mod;
	if(l!=r)
		lazy[x].X = lazy[x].X*val%mod, lazy[x].x = lazy[x].x*val%mod;
}
void GaoAdd(int l, int r, int x, LL val)
{
	tre[x].X = (tre[x].X+val*val%mod*(r-l+1)%mod+2*val*tre[x].x)%mod;
	tre[x].x = (tre[x].x+val*(r-l+1))%mod;
	if(l!=r)
		lazy[x].x = (lazy[x].x+val)%mod;
}
void Update(int l, int r, int x, int a, int b, LL c, int op)
{
	int m;
	if(l>=a && r<=b)
	{
		if(op==4)
			GaoAdd(l, r, x, c);
		else
			GaoX(l, r, x, c);
		return;
	}
	m = (l+r)/2;
	if(lazy[x].X!=1)
		GaoX(l, m, x*2, lazy[x].X), GaoX(m+1, r, x*2+1, lazy[x].X), lazy[x].X = 1;
	if(lazy[x].x)
		GaoAdd(l, m, x*2, lazy[x].x), GaoAdd(m+1, r, x*2+1, lazy[x].x), lazy[x].x = 0;
	if(a<=m)
		Update(l, m, x*2, a, b, c, op);
	if(b>=m+1)
		Update(m+1, r, x*2+1, a, b, c, op);
	tre[x].x = (tre[x*2].x+tre[x*2+1].x)%mod;
	tre[x].X = (tre[x*2].X+tre[x*2+1].X)%mod;
}
LL Query(int l, int r, int x, int a, int b, int op)
{
	int m;
	LL ans = 0;
	if(l>=a && r<=b)
	{
		if(op==1)
			return tre[x].x;
		else
			return tre[x].X;
	}
	m = (l+r)/2;
	if(lazy[x].X!=1)
		GaoX(l, m, x*2, lazy[x].X), GaoX(m+1, r, x*2+1, lazy[x].X), lazy[x].X = 1;
	if(lazy[x].x)
		GaoAdd(l, m, x*2, lazy[x].x), GaoAdd(m+1, r, x*2+1, lazy[x].x), lazy[x].x = 0;
	if(a<=m)
		ans = (ans+Query(l, m, x*2, a, b, op))%mod;
	if(b>=m+1)
		ans = (ans+Query(m+1, r, x*2+1, a, b, op))%mod;
	return ans;
}
void Sech(int u, int p)
{
	int i, v;
	in[u] = ++cnt;
	b[cnt] = a[u];
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(v==p)
			continue;
		Sech(v, u);
	}
	out[u] = cnt;
}
int main(void)
{
	int n, T, i, x, y, op;
	scanf("%d%d", &n, &T);
	for(i=1;i<=n;i++)
		scanf("%d", &a[i]);
	for(i=1;i<=n-1;i++)
	{
		scanf("%d%d", &x, &y);
		G[x].push_back(y);
		G[y].push_back(x);
	}
	Sech(1, 0);
	Create(1, n, 1);
	while(T--)
	{
		scanf("%d", &op);
		if(op==1)
		{
			scanf("%d%d", &x, &y);
			Update(1, n, 1, in[x], out[x], y, 4);
		}
		else
		{
			scanf("%d", &x);
			printf("%lld\n", Query(1, n, 1, in[x], out[x], 2));
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值