D.树上求和
Posted spnooyseed
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D.树上求和相关的知识,希望对你有一定的参考价值。
D.树上求和
给你一棵根为1的有N个节点的树,以及Q次操作。
每次操作诸如:
1 x y:将节点x所在的子树的所有节点的权值加上y
2 x:询问x所在子树的所有节点的权值的平方和,答案模23333后输出
做法倒是好想(但是尽量用结构体数组,不然不好写,原本没有结构体找bug好久,然后又改写的),假设一个点原本是x , 然后加上y , 变大了y * y + 2 * x * y,将一个子树看成dfs序就是一段区间, 那么就是sum += y * y * len + 2 * res * x , len是区间长度,res 是区间和, sum是区间平方和
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <map>
#include <list>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <stack>
#include <set>
#pragma GCC optimize(3 , "Ofast" , "inline")
using namespace std ;
#define ios ios::sync_with_stdio(false) , cin.tie(0) , cout.tie(0)
#define x first
#define y second
#define ls rt << 1
#define rs rt << 1 | 1
typedef long long ll ;
const double esp = 1e-6 , pi = acos(-1) ;
typedef pair<int , int> PII ;
const int N = 1e6 + 10 , INF = 0x3f3f3f3f , mod = 23333 ;
ll in()
{
ll x = 0 , f = 1 ;
char ch = getchar() ;
while(!isdigit(ch)) {if(ch == ‘-‘) f = -1 ; ch = getchar() ;}
while(isdigit(ch)) x = x * 10 + ch - 48 , ch = getchar() ;
return x * f ;
}
int sum[N] , sum1[N] , lazy2[N] , lazy3[N] , cnt = 0 , lf[N] , rg[N] , d[N] , p[N] ;
vector<int> v[N] ;
void dfs(int u , int f){
lf[u] = ++ cnt ;
p[cnt] = d[u] ;
for(auto x : v[u]) {
if(x == f) continue ;
dfs(x , u) ;
}
rg[u] = ++ cnt ;
p[cnt] = d[u] ;
}
struct node {
ll sum , sum1 , lazy , l , r ;
}t[N * 4];
void pushup(int rt){
t[rt].sum = (t[ls].sum + t[rs].sum) % mod ;
t[rt].sum1 = (t[ls].sum1 + t[rs].sum1) % mod ;
return ;
}
void build(int rt , int l , int r){
t[rt].l = l , t[rt].r = r ;
if(l == r) {
t[rt].sum = 1ll * p[l] * p[l] % mod ;
t[rt].sum1 = p[l] % mod ;
return ;
}
int mid = l + r >> 1 ;
build(ls , l , mid) ;
build(rs , mid + 1 , r) ;
pushup(rt) ;
return ;
}
void down(int rt){
if(t[rt].lazy) {
ll &v = t[rt].lazy ;
(t[ls].lazy += v) %= mod ;
(t[rs].lazy += v) %= mod ;
ll ll = t[ls].r - t[ls].l + 1 , rr = t[rs].r - t[rs].l + 1 ; ;
t[ls].sum = (t[ls].sum + ll * v * v % mod + t[ls].sum1 * 2 * v % mod) % mod ;
t[rs].sum = (t[rs].sum + rr * v * v% mod + t[rs].sum1 * 2 * v % mod) % mod ;
t[ls].sum1 = (t[ls].sum1 + ll * v % mod ) % mod ;
t[rs].sum1 = (t[rs].sum1 + rr * v % mod ) % mod ;
v = 0 ;
}
return ;
}
void update(int rt , int l , int r , int k){
if(l <= t[rt].l && t[rt].r <= r) {
t[rt].sum = (t[rt].sum + 1ll * (t[rt].r - t[rt].l + 1) * k % mod * k % mod + t[rt].sum1 * 2 * k % mod) % mod ;
t[rt].sum1 = (t[rt].sum1 + 1ll * (t[rt].r - t[rt].l + 1) * k) % mod ;
t[rt].lazy += k , t[rt].lazy %= mod ;
down(rt) ;
return ;
}
down(rt) ;
int mid = t[rt].l + t[rt].r >> 1;
if(l <= mid) update(ls , l , r , k) ;
if(r > mid) update(rs , l , r , k) ;
pushup(rt) ;
return ;
}
ll query(int rt , int l , int r){
if(t[rt].l >= l && t[rt].r <= r) {
return t[rt].sum ;
}
down(rt) ;
ll mid = t[rt].l + t[rt].r >> 1 , res = 0 ;
if(l <= mid) (res += query(ls , l , r)) %= mod ;
if(r > mid) (res += query(rs , l , r)) %= mod ;
pushup(rt) ;
return res % mod ;
}
int ask(int rt , int l , int r){
if(t[rt].l >= l && t[rt].r <= r) {
return t[rt].sum1 % mod ;
}
down(rt) ;
int mid = t[rt].l + t[rt].r >> 1 , res = 0 ;
if(l <= mid) (res += ask(ls , l , r)) %= mod ;
if(r > mid) (res += ask(rs , l , r)) %= mod ;
pushup(rt) ;
return res ;
}
ll qmi(ll a , ll b){
ll res = 1 ;
while(b)
{
if(b & 1) res = res * a % mod ;
a = a * a % mod ;
b >>= 1 ;
}
return res ;
}
int main()
{
int n = in() , m = in() ;
for(int i = 1; i <= n ;i ++ ) d[i] = in() ;
for(int i = 1; i < n ;i ++ )
{
int a= in() , b = in() ;
v[a].push_back(b) , v[b].push_back(a) ;
}
dfs(1 , 0) ;
build(1 , 1 , cnt) ;
while(m --) {
int op = in() , x = in() , y ;
if(op == 2) cout << query(1 , lf[x] , rg[x]) * qmi(2 , mod - 2) % mod << endl ;
else if(op == 1) y = in() , update(1 , lf[x] , rg[x] , y) ;
else cout << ask(1 , lf[x] , rg[x]) << " C " << endl ;
}
return 0 ;
}
/*
6 10
10000 10000 100000 10000 10000 100000
1 2
1 3
2 5
2 6
5 4
1 1 100000
2 1
1 5 12000
2 1
1 2 10
2 1
1 4 10300
2 1
2 3
2 4
*/
以上是关于D.树上求和的主要内容,如果未能解决你的问题,请参考以下文章