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 为根的子树中所有点的点权都 ...
随机推荐
- Greenplum介绍-table
GP中的table和其它关系型数据表是一样的,除了数据被分布在不同的segment以外. 建表时需定义以下几个方面:1. 指定列和数据类型2. 约束3. 分布策略4. 数据存储方式5. 大表分区策略 ...
- python--初识html前端
一.HTML文档结构 最基本的HTML文档: <!DOCTYPE html> <html lang="zh-CN"> #这个lang表示语言,zh-CN是中 ...
- (原)剑指offer之位运算
题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路: count为1的位数,初始为零 每次右移一为,与1做与运算,结果不为零说明最后一位为1 c++代码如下 in ...
- 基础训练 FJ的字符串
FJ的字符串 #include<iostream> #include<string.h> using namespace std; int main(){ string str ...
- 排序算法C语言实现——冒泡、快排、堆排对比
对冒泡.快排.堆排这3个算法做了验证,结果分析如下: 一.结果分析 时间消耗:快排 < 堆排 < 冒泡. 空间消耗:冒泡O(1) = 堆排O(1) < 快排O(logn)~O(n) ...
- JavaScript注释
JavaScript注释有两种方式: 1.单行注释. 2.多行注释. 单行注释 单行注释以“//”开头. <script type="text/javascript"> ...
- 多重部分和 poj1742
Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...
- php文档php-fpm.conf配置
cat php-fpm.conf|grep -v "^;"|grep -v "^$" [global] pid = run/php-fpm.pid //pi ...
- [BZOJ1595] [Usaco2008 Jan]人工湖(单调栈)
传送门 好难的题..至少对我来说. 这题就是模拟从最低的平台注水,然后将最低的填满以后从最低的平台向两边扩展,每次找最近的最低的平台h,然后将水填到h高度. 栈里存的是向外扩展的时候,有时会遇到高度递 ...
- POJ 1067: Wythoff Game【博弈】
经典的威佐夫博奕把黄金分割常数乘以k(k=m-n)即为奇异点,此时奇异点是用小数据观察出来的,具体的数学证明,观察到黄金分割常数是无理数,再加上高斯函数[kφ]的形势将自然数分割成两个等价类很容易想到 ...