BZOJ 4034 [HAOI2015]树上操作(树链剖分)
题目链接 BZOJ4034
这道题树链剖分其实就可以了。
单点更新没问题。
相当于更新
[f[x], f[x]]这个区间。
f[x]表示树链剖分之后每个点的新的标号。
区间更新的话类似DFS序,求出所对应的区间。
也就是[f[x], f[x] + size[x] - 1]。
给这个区间加上a即可。
询问的时候有两种方法,一个是直接套模板。
还有一种方法是,因为是查询x到1的权值和,
所以跟着top[x]走就可以了。
第一种方法:
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R typedef long long LL; const int N = 300010; LL a[N], sum[N << 2], lazy[N << 2], y;
int f[N], fp[N], son[N], deep[N], father[N], sz[N], top[N];
int x, tot, n, m, op;
vector <int> v[N]; void dfs1(int x, int fa, int dep){
deep[x] = dep;
father[x] = fa;
son[x] = 0;
sz[x] = 1;
int ct = (int)v[x].size();
rep(i, 0, ct - 1){
int u = v[x][i];
if (u == fa) continue;
dfs1(u, x, dep + 1);
sz[x] += sz[u];
if (sz[son[x]] < sz[u]) son[x] = u;
}
} void dfs2(int x, int tp){
top[x] = tp;
f[x] = ++tot;
fp[f[x]] = x;
if (son[x]) dfs2(son[x], tp);
int ct = (int)v[x].size();
rep(i, 0, ct - 1){
int u = v[x][i];
if (u == father[x] || u == son[x]) continue;
dfs2(u, u);
}
} inline void pushup(int i){
sum[i] = sum[i << 1] + sum[i << 1 | 1];
} inline void pushdown(int i, int L, int R){
int mid = (L + R) >> 1;
lazy[i << 1] += lazy[i];
sum[i << 1] += lazy[i] * (mid - L + 1);
lazy[i << 1 | 1] += lazy[i];
sum[i << 1 | 1] += lazy[i] * (R - mid);
lazy[i] = 0;
} void build(int i, int L, int R){
if (L == R){ sum[i] = a[fp[L]]; return; }
int mid = (L + R) >> 1;
build(lson);
build(rson);
pushup(i);
} void update(int i, int L, int R, int l, int r, LL val){
if (l == L && R == r){
sum[i] += val * (R - L + 1);
lazy[i] += val;
return ;
} if (lazy[i]) pushdown(i, L, R); int mid = (L + R) >> 1;
if (r <= mid) update(lson, l, r, val);
else if (l > mid) update(rson, l, r, val);
else{
update(lson, l, mid, val);
update(rson, mid + 1, r, val);
} pushup(i);
} LL query_sum(int i, int L, int R, int l, int r){
pushdown(i, L, R);
if (L == l && R == r) return sum[i];
int mid = (L + R) >> 1;
if (r <= mid) return query_sum(lson, l, r);
else if (l > mid) return query_sum(rson, l, r);
else return query_sum(lson, l, mid) + query_sum(rson, mid + 1, r);
} LL find_sum(int x, int y){
int f1 = top[x], f2 = top[y];
LL ret = 0;
for (; f1 != f2; ){
if (deep[f1] < deep[f2]) swap(f1, f2), swap(x, y);
ret += query_sum(1, 1, n, f[f1], f[x]);
x = father[f1], f1 = top[x];
} if (x == y) return ret + query_sum(1, 1, n, f[x], f[y]);
if (deep[x] > deep[y]) swap(x, y);
return ret + query_sum(1, 1, n, f[x], f[y]);
} int main(){ scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%lld", a + i);
rep(i, 2, n){
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
} dfs1(1, 0, 0);
dfs2(1, 1); build(1, 1, n); while (m--){
scanf("%d", &op);
if (op == 1){
scanf("%d%lld", &x, &y);
update(1, 1, n, f[x], f[x], y);
} else if (op == 2){
scanf("%d%lld", &x, &y);
update(1, 1, n, f[x], f[x] + sz[x] - 1, y);
} else{
scanf("%d", &x);
printf("%lld\n", find_sum(x, 1));
}
} return 0;
}
第二种方法:
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define lson i << 1, L, mid
#define rson i << 1 | 1, mid + 1, R typedef long long LL; const int N = 300010; LL a[N], sum[N << 2], lazy[N << 2], y;
int f[N], fp[N], son[N], deep[N], father[N], sz[N], top[N];
int x, tot, n, m, op;
vector <int> v[N]; void dfs1(int x, int fa, int dep){
deep[x] = dep;
father[x] = fa;
son[x] = 0;
sz[x] = 1;
int ct = (int)v[x].size();
rep(i, 0, ct - 1){
int u = v[x][i];
if (u == fa) continue;
dfs1(u, x, dep + 1);
sz[x] += sz[u];
if (sz[son[x]] < sz[u]) son[x] = u;
}
} void dfs2(int x, int tp){
top[x] = tp;
f[x] = ++tot;
fp[f[x]] = x;
if (son[x]) dfs2(son[x], tp);
int ct = (int)v[x].size();
rep(i, 0, ct - 1){
int u = v[x][i];
if (u == father[x] || u == son[x]) continue;
dfs2(u, u);
}
} inline void pushup(int i){ sum[i] = sum[i << 1] + sum[i << 1 | 1]; } inline void pushdown(int i, int L, int R){
sum[i] += lazy[i] * (R - L + 1);
lazy[i << 1] += lazy[i];
lazy[i << 1 | 1] += lazy[i];
lazy[i] = 0;
} void build(int i, int L, int R){
if (L == R){ sum[i] = a[fp[L]]; return; }
int mid = (L + R) >> 1;
build(lson);
build(rson);
pushup(i);
} void update(int i, int L, int R, int l, int r, LL val){
if (l == L && R == r){
lazy[i] += val;
return ;
} int mid = (L + R) >> 1;
if (r <= mid) update(lson, l, r, val);
else if (l > mid) update(rson, l, r, val);
else{
update(lson, l, mid, val);
update(rson, mid + 1, r, val);
} pushdown(i << 1, L, mid);
pushdown(i << 1 | 1, mid + 1, R);
pushup(i);
} LL query_sum(int i, int L, int R, int l, int r){
pushdown(i, L, R);
if (L == l && R == r) return sum[i];
int mid = (L + R) >> 1;
if (r <= mid) return query_sum(lson, l, r);
else if (l > mid) return query_sum(rson, l, r);
else return query_sum(lson, l, mid) + query_sum(rson, mid + 1, r);
} int main(){ scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%lld", a + i);
rep(i, 2, n){
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
} dfs1(1, 0, 0);
dfs2(1, 1); build(1, 1, n); while (m--){
scanf("%d", &op);
if (op == 1){
scanf("%d%lld", &x, &y);
update(1, 1, n, f[x], f[x], y);
} else if (op == 2){
scanf("%d%lld", &x, &y);
update(1, 1, n, f[x], f[x] + sz[x] - 1, y);
} else{
scanf("%d", &x);
LL ans = 0;
for (int i = x; i; i = father[top[i]])
ans += query_sum(1, 1, n, f[top[i]], f[i]);
printf("%lld\n", ans);
}
} return 0;
}
BZOJ 4034 [HAOI2015]树上操作(树链剖分)的更多相关文章
- bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4352 Solved: 1387[Submit][Stat ...
- bzoj 4034: [HAOI2015]树上操作——树链剖分
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...
- BZOJ 4034[HAOI2015]树上操作(树链剖分)
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点 ...
- bzoj4034[HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6163 Solved: 2025[Submit][Stat ...
- bzoj 4034 [HAOI2015] T2(树链剖分,线段树)
4034: [HAOI2015]T2 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1536 Solved: 508[Submit][Status] ...
- BZOJ 4034 [HAOI2015]T2(树链剖分)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4034 [题目大意] 有一棵点数为 N 的树,以点 1 为根,且树点有边权. 有 M 个 ...
- 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树
[BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...
- BZOJ4034 [HAOI2015]树上操作 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...
- P3178 [HAOI2015]树上操作 树链剖分
这个题就是一道树链剖分的裸题,但是需要有一个魔性操作___编号数组需要开longlong!!!震惊!真的神奇. 题干: 题目描述 有一棵点数为 N 的树,以点 为根,且树点有边权.然后有 M 个操作, ...
- BZOJ4034[HAOI2015]树上操作——树链剖分+线段树
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...
随机推荐
- 当然,perl等脚本服务器是一般默认安装了,你入侵了一台主机,总不能先装配 Java 环境然后再开干吧?
转自:https://www.zhihu.com/question/20173592 当然,perl等脚本服务器是一般默认安装了,你入侵了一台主机,总不能先装配 Java 环境然后再开干吧?
- 【Java_基础】java中的多态性
方法的重载.重写和动态链接构成了java的多态性. 1.方法的重载 同一个类中多个同名但形参有所差异的方法,在调用时会根据参数的不同做出选择. 2.方法的重写 子类中重新定义了父类的方法,有关方法重写 ...
- MySQL开启日志跟踪
在开发过程中有时候会遇到sql相关的问题,但是有时候代码中不会直接看到真实的sql,想要看到mysql中实际执行的是什么sql,可以通过开启日志跟踪方式查看. 1 开启日志跟踪 SET GLOBAL ...
- springboot 修炼之路
网上无意中发现一份关于springboot的教程说明,说的很详细,大家可以参考.具体地址:http://www.spring4all.com/article/246
- Python爬虫环境常用库安装
1:urllib urllib.request这两个库是python自带的库,不需要重新安装,在python中输入如下代码: import urllibimport urllib.requestres ...
- 【linux】 【网络】【转发】服务器版自定义安装无法有线上网问题
- python爬虫入门六:Selenium库
在我们爬取网页过程中,经常发现我们想要获得的数据并不能简单的通过解析HTML代码获取,这些数据是通过AJAX异步加载方式或经过JS渲染后才呈现在页面上显示出来. selenuim是一种自动化测试工具, ...
- expdp / impdp 用法详解(Oracle)
一 .关于expdp和impdp 使用EXPDP和IMPDP时应该注意的事项: EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用. EXPDP和IMPDP是服务端的工 ...
- 【javascript面试题】之一
1.求y和z的值是多少?<script type="text/javascript">var x = 1;var y = 0;var z = 0;function ad ...
- Silverlight调用GP工具实现缓冲分析
目的: 在地图上点击一个点生成一个缓冲区. 1.制作GP工具: GP工具制作按照http://help.arcgis.com/zh-cn/arcgisdesktop/10.0/help/index.h ...