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.树上求和的主要内容,如果未能解决你的问题,请参考以下文章

luogu P1352ybtoj 树形DP课堂过关 例题1树上求和 & 没有上司的舞会

HDU 6200 2017沈阳网络赛 树上区间更新,求和

[搜索]求和VII

求和VII

「BJOI2018」求和

树上数据结构——LCT