一开始没看懂计算答案的第四部和update2,很迷。然后一直推敲之后才发下我计算的时候漏掉一个关键点。没有把加值的影响放到父节点上。

#include<bits/stdc++.h>
#define M ((l + r) / 2)
#define ls (rt << 1)
#define rs ((rt << 1) | 1)
#define UI unsigned int
using namespace std; const int maxn = 6e5 + ;
vector<int>Gra[maxn];
UI f[maxn], c[maxn], sz[maxn], w[maxn], sum[maxn << ], add[maxn], cntSon[maxn], cntSeson[maxn];
int fa[maxn], N, top[maxn], hSon[maxn];
int edn[maxn], stn[maxn]; /**
stn dfs序的起点, edn dfs序的终点,hSon 重树,add 加重, cntSon 直接子节点数量
sz 树的总大小, cntSeson 2层子节点的总数量, c 子树重复计算个数,
f 未进行操作的子树总值 top 重链的父节点。
**/ ///主要是计算初始值
void dfs1(int u) {
cntSeson[u] = cntSon[u] = hSon[u] = c[u] =;
sz[u] = ;
for(auto v: Gra[u]) {
if(v == fa[u]) continue;
dfs1(v);
sz[u] += sz[v];
cntSon[u] ++;
cntSeson[u] += cntSon[v] + ;
c[u] += sz[v] * cntSon[v];
if(sz[hSon[u]] < sz[v]) hSon[u] = v;
}
f[u] = w[u] * (sz[u] + );
for(auto v: Gra[u]) {
if(v == fa[u]) continue;
f[u] += (sz[u] - sz[v]) * w[v];
w[u] += w[v];
}
} ///dfs序,以及最重要的重树父节点
void dfs2(int u, int t) {
top[u] = t;
stn[u] = ++N;
if(hSon[u]) dfs2(hSon[u], t);
for(auto v: Gra[u]) {
if(v == fa[u] || hSon[u] == v) continue;
dfs2(v, v);
}
edn[u] = N;
} ///查询线段树上的价值
int query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) return sum[rt];
int ret = ;
if(M >= L) ret += query(L, R, l, M, ls);
if(M < R) ret += query(L, R, M + , r, rs);
return ret;
} ///作用之后对父节点的影响
void update1(int x, int val) {
while(top[x] != top[]) {
int v = top[x], u = fa[v];
f[u] += (sz[u] - sz[v]) * val;
x = u;
}
} ///存加的价值的影响范围
void update2(int p, UI val, int l, int r, int rt) {
sum[rt] += val;
if(l == r) return ;
if(M >= p) update2(p, val, l, M, ls);
else update2(p, val, M + , r, rs);
} int main() {
freopen("data.txt", "r", stdin);
int n, m, st, ed;
while(~scanf("%d%d", &n, &m)) {
memset(add, , sizeof(add));
memset(sum, , sizeof(sum));
N = ;
for(int i = ; i <= n; i ++)
Gra[i].clear();
for(int i = ; i <= n; i ++) {
scanf("%d", &ed);
fa[i] = ed;
Gra[ed].push_back(i);
Gra[i].push_back(ed);
}
for(int i = ; i <= n; i ++)
scanf("%u", &w[i]);
dfs1();
dfs2(, );
while(m -- ) {
int op, u;
UI x;
scanf("%d", &op);
if(op == ) {
scanf("%d%u", &u, &x);
add[u] += x;
///沿着重树往上预计算重树点价值的作用,之后就不用重复计算这一部分了,这样重树这里就可以成为一个撬棍
update1(u, x * ( + cntSeson[u]));
///将每个点的填加的价值放进去线段树
update2(stn[u], x * (cntSeson[u]+ ), , n, );
} else {
scanf("%d", &u);
UI ans = f[u];
///加值时作用在当前节点上的情况
ans += add[u] * ( + sz[u] * cntSeson[u] - c[u]);
if(fa[u])///加值时作用在子节点上的情况
ans += add[fa[u]] * ( + sz[u] * cntSon[u]);
if(fa[fa[u]])///加值时作用在孙子节点上的情况
ans += add[fa[fa[u]]] * ( + sz[u]);
if(hSon[u])///计算除重树内加值的价值,因为已经在update1计算过了到f中了
ans += (sz[u] - sz[hSon[u]]) * query(stn[hSon[u]], edn[hSon[u]], , n, );
printf("%u\n",ans);
}
}
}
return ;
}

Gardener Bo (树剖 + 问题分解)的更多相关文章

  1. 【61测试】【dp】【二分】【前缀和】【树剖】

    不要问我为什么昨天考的今天才贴解题报告.. 第一题: 给定3个字符串,求它们的最长公共子序列. 解: 考试时知道肯定是LCS的二维再加一维,用三维,可天堂有路你不走,地狱无门你偏来...灵机一动想出来 ...

  2. hdu_5221_Occupation(树剖)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5221 题意:给你一棵树,每个节点有一定的值,有三种操作: 1 x y 表示占领树上x-y的所有节点,2 ...

  3. 【树链剖分】洛谷P3384树剖模板

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  4. 【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】

    题目链接: TP 题解:   可能是我比较纱布,看不懂题解,只好自己想了…… 先附一个离线版本题解[Ivan] 我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案. 首先LC ...

  5. BZOJ_2238_Mst_树剖+线段树

    BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...

  6. BZOJ_3626_[LNOI2014]LCA_离线+树剖

    BZOJ_3626_[LNOI2014]LCA_离线+树剖 题意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度, ...

  7. BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树

    BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树 题意: 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastan ...

  8. BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树

    BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...

  9. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

随机推荐

  1. 在Java程序中读写windows共享文件夹

    摘要 使用Java通过JCIFS框架读写共享文件夹,使用SMB协议,并支持域认证. 项目常常需要有访问共享文件夹的需求,例如读取共享文件夹存储的视频.照片和PPT等文件.那么如何使用Java读写Win ...

  2. TZOJ 5640: 数据结构实验:仓库管理

    描述 某百货公司仓库中有一批电视机,按其价格严格从低到高的次序,以链表(链表含头结点)的形式存储于计算机中,链表的每个结点表示同样价格的电视机台数.现在又有m台价格为x元的电视机准备入库,请将其加入到 ...

  3. caffe 测试时间报错 Aborted at unix time

    今天测试时间报错,具体如下图: 在网上查了一下,大概的原因是由于程序中使用了随机函数造成的,后来检查了一下prototxt中有可能含有随机数的地方,去掉之后就可以了,包括shuffle:true,以及 ...

  4. Spring 配置文件出现异常!

    spring配置文件错误 Referenced file contains errors (http://www.springframework.org/schema/beans/spring-bea ...

  5. composer错误提示Cloning failed using an ssh key for authentication的解决方法

    早上ytkah在测试laravel用composer安装一些插件时出现了一些错误,提示如下,是github的ssh密匙认证错误,提示要重新生成token,然后保存在/root/.config/comp ...

  6. 20170712 SQL Server 日志文件收索

    -- 1 日志文件增长过快,未进行任务计划截断备份 造成文件过大199G 左右,而可用空间不足8% -- 2 日志备份之前,需要一次完整备份 再进行截断备份 出现可用空间99% 此时可以选择收索数据库 ...

  7. LongAdder,AtomicIntegerFieldUpdater深入研究

    从LongAdder看更高效的无锁实现 AtomicIntegerFieldUpdater字段原子更新类 div:not([id]){display:none;} --> ul{padding: ...

  8. file相关方法

    File文件,getAbsolutePath方法 public String getAbsolutePath() 该方法的作用是获得当前文件或文件夹的绝对路径.例如c:\test\1.t则返回c:\t ...

  9. C 语言循环结构

      25.有如下程序 main() { int i,sum; for(i=1;i<=3;sum++) sum+=i; printf("%d\n",sum); } 该程序的执行 ...

  10. 使用awk处理文本

    http://blog.wuxu92.com/using-awk/ 在Liux下我们经常需要对一些文本文档做一些处理,尤其像从日志里提取一些数据,这是我们一般会用awk工具和sed工具去实现需求,这里 ...