Description

传送门

给出一个n个点的树,1号节点为根节点,每个点有一个权值
你需要支持以下操作
1.将以u为根的子树内节点(包括u)的权值加val

2.将(u, v)路径上的节点权值加val
3.询问(u, v)路径上节点的权值两两相乘的和
 

Solution

维护 平方和与 数值和

修改 : 假如修改时有节点a, b, c, 增加t, 那么$sumsq = a^2 + b^2 + c^2 + 2*t*(a + b+c) + 3 * t^2$

所以对于所有的修改, $sumsq = sumsq + 2*t*sum + (r-l+1)*t^2$

这样平方和与数值和就可以维护了

查询只需要输出 $(sum * sum - sumsq) / 2$

Code

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define rd read()
#define lson nd << 1
#define rson nd << 1 | 1
using namespace std; const int N = 1e5 + ;
const ll mod = 1e9 + ; int n, m;
int top[N], size[N], son[N], f[N], dep[N], cnt;
int head[N], tot;
int A[N], a[N], id[N];
int Li[N << ], Ri[N << ];
ll sum[N << ], sum2[N << ], inv, add[N << ]; struct edge{
int nxt, to;
}e[N << ]; int read() {
int X = , p = ; char c = getchar();
for(; c > '' || c < ''; c = getchar()) if(c == '-') p = -;
for(; c >= '' && c <= ''; c = getchar()) X = X * + c - '';
return X * p;
} void added(int u, int v) {
e[++tot].to = v;
e[tot].nxt = head[u];
head[u] = tot;
} void dfs1(int u) {
size[u] = ;
for(int i = head[u]; i; i = e[i].nxt) {
int nt = e[i].to;
if(nt == f[u]) continue;
dep[nt] = dep[u] + ;
f[nt] = u;
dfs1(nt);
size[u] += size[nt];
if(size[nt] > size[son[u]]) son[u] = nt;
}
} void dfs2(int u) {
id[u] = ++cnt;
A[cnt] = a[u];
if(!son[u]) return;
top[son[u]] = top[u];
dfs2(son[u]);
for(int i = head[u]; i; i = e[i].nxt) {
int nt = e[i].to;
if(nt == f[u] || nt == son[u]) continue;
top[nt] = nt;
dfs2(nt);
}
} void pushdown(int nd) {
if(add[nd]) {
sum2[lson] += ( * sum[lson] * add[nd] % mod + (Ri[lson] - Li[lson] + ) * add[nd] % mod * add[nd] % mod) % mod;
sum2[lson] %= mod;
sum2[rson] += ( * sum[rson] * add[nd] % mod + (Ri[rson] - Li[rson] + ) * add[nd] % mod * add[nd] % mod) % mod;
sum2[rson] %= mod; sum[lson] += (Ri[lson] - Li[lson] + ) * add[nd] % mod;
sum[lson] %= mod;
sum[rson] += (Ri[rson] - Li[rson] + ) * add[nd] % mod;
sum[rson] %= mod; add[lson] += add[nd];
add[rson] += add[nd];
add[lson] %= mod;
add[rson] %= mod;
add[nd] = ;
}
} void update(int nd) {
sum[nd] = (sum[lson] + sum[rson]) % mod;
sum2[nd] = (sum2[lson] + sum2[rson]) % mod;
} void build(int l, int r, int nd) {
if(l == r) {
Li[nd] = l;
Ri[nd] = r;
sum[nd] = A[l];
sum2[nd] = A[l] * A[l] % mod;
return;
}
Li[nd] = l;
Ri[nd] = r;
int mid =(l + r) >> ;
build(l, mid, lson);
build(mid + , r, rson);
update(nd);
} void modify(int L, int R, int d, int l, int r, int nd) {
if(L <= l && r <= R) {
sum2[nd] += ( * sum[nd] * d % mod + (r - l + ) * d % mod * d % mod) % mod;
sum2[nd] %= mod;
sum[nd] += 1LL * d * (r - l + ) % mod;
sum[nd] %= mod;
add[nd] += d;
add[nd] %= mod;
return;
}
pushdown(nd);
int mid = (l + r) >> ;
if(mid >= L) modify(L, R, d, l, mid, lson);
if(mid < R) modify(L, R, d, mid + , r, rson);
update(nd);
} ll query(int L, int R, int l, int r, int nd) {
if(L <= l && r <= R) return sum[nd];
int mid = (l + r) >> ;
ll re = ;
pushdown(nd);
if(mid >= L) re = (re + query(L, R, l, mid, lson)) % mod;
if(mid < R) re = (re + query(L, R, mid + , r, rson)) % mod;
return re;
} ll query2(int L, int R, int l, int r, int nd) {
if(L <= l && r <= R) return sum2[nd];
int mid = (l + r) >> ;
ll re = ;
pushdown(nd);
if(mid >= L) re = (re + query2(L, R, l, mid, lson)) % mod;
if(mid < R) re = (re + query2(L, R, mid + , r, rson)) % mod;
return re;
} ll query_po(int x, int y) {
ll re = , tmp, sum = ;
for(; top[x] != top[y];) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
tmp = query(id[top[x]], id[x], , n, );
sum = (sum + tmp % mod) % mod;
tmp = query2(id[top[x]], id[x], , n, );
re = (re - tmp) % mod;
x = f[top[x]];
}
if(dep[x] < dep[y]) swap(x, y);
tmp = query(id[y], id[x], , n, );
sum = (sum + tmp) % mod;
tmp = query2(id[y], id[x], , n, );
re = (re - tmp) % mod;
re = (re + sum * sum % mod) % mod;
re = (re % mod + mod) % mod;
re = re * inv % mod;
return re;
} void modify_po(int x, int y, int d) {
for(; top[x] != top[y];) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
modify(id[top[x]], id[x], d, , n, );
x = f[top[x]];
}
if(dep[x] < dep[y]) swap(x, y);
modify(id[y], id[x], d, , n, );
} ll fc(ll ta, ll b) {
ll re = ;
for(; b; b >>= , ta = (ta + ta) % mod) if( b & ) re = (re + ta) % mod;
return re;
} ll fpow(ll ta, ll b) {
ll re = ;
for(; b; b >>= , ta = fc(ta, ta)) if(b & ) re = fc(re, ta);
return re;
} int main()
{
n = rd; m = rd;
for(int i = ; i <= n; ++i) a[i] = rd;
for(int i = ; i < n; ++i) {
int u = rd, v = rd;
added(u, v); added(v, u);
}
dfs1();
top[] = ;
dfs2();
build(, n, );
inv = fpow(, mod - );
for(int i = ; i <= m; ++i) {
int k = rd;
if(k == ) {
int u = rd, val = rd;
modify(id[u], id[u] + size[u] - , val, , n, );
}
if(k == ) {
int u = rd, v = rd, val = rd;
modify_po(u, v, val);
}
if(k == ) {
int u = rd, v = rd;
printf("%lld\n", query_po(u, v));
}
}
}

Nowcoder 练习赛26E 树上路径 - 树剖的更多相关文章

  1. [GXOI/GZOI2019]旧词(树上差分+树剖)

    前置芝士:[LNOI2014]LCA 要是这题放HNOI就好了 原题:\(\sum_{l≤i≤r}dep[LCA(i,z)]\) 这题:\(\sum_{i≤r}dep[LCA(i,z)]^k\) 对于 ...

  2. bzoj4034: [HAOI2015]树上操作(树剖)

    4034: [HAOI2015]树上操作 题目:传送门 题解: 树剖裸题: 麻烦一点的就只有子树修改(其实一点也不),因为子树编号连续啊,直接改段(记录编号最小和最大) 开个long long 水模版 ...

  3. [GX/GZOI2019]旧词(树上差分+树剖+线段树)

    考虑k=1的做法:这是一道原题,我还写过题解,其实挺水的,但当时我菜还是看题解的:https://www.cnblogs.com/hfctf0210/p/10187947.html.其实就是树上差分后 ...

  4. 洛谷P3258 [JLOI2014]松鼠的新家(树上差分+树剖)

    题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...

  5. BZOJ 2243 [SDOI2011]染色:树剖【维护路径上颜色段】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径 ...

  6. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  7. POJ3417Network(LCA+树上查分||树剖+线段树)

    Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has jus ...

  8. bzoj 4034 [HAOI2015]树上操作 入栈出栈序+线段树 / 树剖 维护到根距离和

    题目大意 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...

  9. [ZJOI2019]语言——树剖+树上差分+线段树合并

    原题链接戳这儿 SOLUTION 考虑一种非常\(naive\)的统计方法,就是对于每一个点\(u\),我们维护它能到达的点集\(S_u\),最后答案就是\(\frac{\sum\limits_{i= ...

随机推荐

  1. nginx 增加 lua模块

    Nginx中的stub_status模块主要用于查看Nginx的一些状态信息. 本模块默认是不会编译进Nginx的,如果你要使用该模块,则要在编译安装Nginx时指定: ./configure –wi ...

  2. 安装linux版zabbix客户端

    安装linux版zabbix客户端 一.下载客户端 查看centos系统内核版本 cat /proc/version 如上图,就选择Linux 2.6系统对应的agent版本程序 打开官网:https ...

  3. linux安装jdk以及tomcat

    一.卸载旧jdk 1.检测原OPENJDK版本 java -version 查看是否安装了jdk,并且是什么版本 2.进一步查看JDK信息 rpm -qa|grep java tzdata-java- ...

  4. Java中构造函数传参数在基本数据类型和引用类型之间的区别

    Java中构造函数传参数在基本数据类型和引用类型的区别 如果构造函数中穿的参数为基本数据类型,如果在函数中没有返回值,在调用的时候不会发生改变:而如果是引用类型,改变的是存储的位置,所有不管有没有返回 ...

  5. GraphicsTier

    [GraphicsTier] 1.enum GraphicsTier 2.enum ShaderQuality 3.enum BuildTargetGroup 4.EditorGraphicsSett ...

  6. python3 文件读写,编码错误UnicodeDecodeError

    问题:python3 with open文件进行读写,报编码错误 /usr/local/Cellar/python3/3.5.2/Frameworks/Python.framework/Version ...

  7. vue element upload上传、清除等

    如果项目中可以使用file-list,那我们可以点击file-list删除文件列表: 有时候项目中是不要这个文件列表的,所以在上传成功以后,文件列表一直存在,要重新上传就必须刷新页面,所以我们需要手动 ...

  8. Centos 7 下 Mysql 5.7 Galera Cluster 集群部署

     一.介绍 传统架构的使用,一直被人们所诟病,因为MySQL的主从模式,天生的不能完全保证数据一致,很多大公司会花很大人力物力去解决这个问题,而效果却一般,可以说,只能是通过牺牲性能,来获得数据一致性 ...

  9. mysql中插入序列表

    利用序列表来实现列转行:CREATE TABLE sequence(id INT UNSIGNED NOT NULL auto_increment PRIMARY KEY)往里面插入数据 INSERT ...

  10. Codeforces Beta Round #63 (Div. 2)

    Codeforces Beta Round #63 (Div. 2) http://codeforces.com/contest/69 A #include<bits/stdc++.h> ...