Nowcoder 练习赛26E 树上路径 - 树剖
Description
给出一个n个点的树,1号节点为根节点,每个点有一个权值
你需要支持以下操作
1.将以u为根的子树内节点(包括u)的权值加val
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 树上路径 - 树剖的更多相关文章
- [GXOI/GZOI2019]旧词(树上差分+树剖)
前置芝士:[LNOI2014]LCA 要是这题放HNOI就好了 原题:\(\sum_{l≤i≤r}dep[LCA(i,z)]\) 这题:\(\sum_{i≤r}dep[LCA(i,z)]^k\) 对于 ...
- bzoj4034: [HAOI2015]树上操作(树剖)
4034: [HAOI2015]树上操作 题目:传送门 题解: 树剖裸题: 麻烦一点的就只有子树修改(其实一点也不),因为子树编号连续啊,直接改段(记录编号最小和最大) 开个long long 水模版 ...
- [GX/GZOI2019]旧词(树上差分+树剖+线段树)
考虑k=1的做法:这是一道原题,我还写过题解,其实挺水的,但当时我菜还是看题解的:https://www.cnblogs.com/hfctf0210/p/10187947.html.其实就是树上差分后 ...
- 洛谷P3258 [JLOI2014]松鼠的新家(树上差分+树剖)
题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...
- BZOJ 2243 [SDOI2011]染色:树剖【维护路径上颜色段】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2243 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径 ...
- 【bzoj4699】树上的最短路(树剖+线段树优化建图)
题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...
- POJ3417Network(LCA+树上查分||树剖+线段树)
Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has jus ...
- bzoj 4034 [HAOI2015]树上操作 入栈出栈序+线段树 / 树剖 维护到根距离和
题目大意 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...
- [ZJOI2019]语言——树剖+树上差分+线段树合并
原题链接戳这儿 SOLUTION 考虑一种非常\(naive\)的统计方法,就是对于每一个点\(u\),我们维护它能到达的点集\(S_u\),最后答案就是\(\frac{\sum\limits_{i= ...
随机推荐
- jquery iframe父子框架中的元素访问方法
在web开发中,经常会用到iframe,难免会碰到需要在父窗口中使用iframe中的元素.或者在iframe框架中使用父窗口的元素 js 在父窗口中获取iframe中的元素 1. 格式:window. ...
- redis 存储java对象 两种方式
根据redis的存储原理,Redis的key和value都支持二进制安全的字符串 1.利用序列化和反序列化的方式存储java对象我们可以通过对象的序列化与反序列化完成存储于取出,这样就可以使用redi ...
- 消息队列RabbitMQ与Spring
1.RabbitMQ简介 RabbitMQ是流行的开源消息队列系统,用erlang语言开发.RabbitMQ是AMQP(高级消息队列协议)的标准实现. 官网:http://www.rabbitmq.c ...
- CRTD模拟MFG工单进行绑定优化
需求:按单按库生产的CRTD状态半成品工单重复创建问题 绑定成功案例: SELECT DEMANDLINEID,SUPPLYORDERID,DEMANDORDERID,QTYALLOCATED,ITE ...
- python 分词
import jieba text = '我来到北京清华大学' default_mode =jieba.cut(text) full_mode = jieba.cut(text,cut_all=Tru ...
- python--第三天总结
[collection系列]1.计数器(counter) Counter是对字典类型的补充,用于追踪值的出现次数. ps:具备字典的所有功能 + 自己的功能 c = Counter('abcdeabc ...
- 五:python 对象类型详解二:字符串(上)
一:常量字符串 常量字符串用起来相对简单,也许最复杂的事情就是在代码中有如此多的方法来编写它们. eg:单引号:'spam"m' , 双引号: “spa'm” , 三引号:‘’‘... ...
- perl-我的第一个程序
1.问题描述: 总共90位长度的位流数据,其中只有5位的数据为1,其余位全部为0.统计好多组5位的简化数据(每一位之间空格隔开,每一组一行),将其扩展到90位. #!D:/EDA/Perl/bin $ ...
- DRF的视图和路由
DRF的视图 APIView Django中写CBV的时候继承的是View,rest_framework继承的是APIView, urlpatterns = [ url(r'^book$', Book ...
- Stealth潜行风格游戏源码(Unity5x)
官方的Stealth画质看起来不错.Unity 官方说Stealth样例属于中等难度,通过学习Stealth,可以获得: Create a fully functioning level of a ...