题意:

树上n个点,支持单点修改,区间查询最大值和sum和。


思路:

此处只讲大体思路,树链剖分的详细原理请移步
https://blog.csdn.net/qq_41552508/article/details/88576338

单点修改和单点查询,就是直接在线段树上修改和查询 top[x]top[x]top[x],即该点的 dfsdfsdfs 序,即该点在线段树区间上的位置。

区间修改和区间查询,就是先处理出两点之间的树链,由于树链上的点的 dfsdfsdfs 序,即在线段树区间上的位置都是连续的,因此直接对树链进行线段树的常规修改、更新操作即可。

下面的代码包括了区间修改和单点修改,以及区间查询最大值和最值。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
#define int long long
const db EPS = 1e-9;
const int N = 1e5+100;
using namespace std;struct Edge { int next,to;} e[2*N];
struct Node { int l,r,ls,rs,sum,lazy,maxn;} t[2*N];
int n,m,root,rt,mod,val[N],head[N],tot,fa[N],d[N],son[N],size[N],top[N],id[N],rk[N];
//top[x]: x节点所在链的顶端节点, id[x]: 节点dfs序, rk[x]: dfs序对应的节点
//val[x]: 每个点初始权值, fa[x]: 每个点父节点, d[x]: 节点深度, size[x]: 节点子树大小
//rt: 线段树根节点编号
void init(){memset(head,0,sizeof head);tot = 1, size[0] = 0;
}void add(int x, int y){e[++tot].next = head[x], e[tot].to = y, head[x] = tot;
}void dfs1(int x){  //求出每个点的子树大小、深度、重儿子size[x] = 1, d[x] = d[fa[x]]+1, son[x] = 0;for(int v,i = head[x]; i; i = e[i].next)if((v = e[i].to)!=fa[x]){fa[v] = x, dfs1(v), size[x] += size[v];if(size[son[x]] < size[v])son[x] = v;}
}void dfs2(int x, int tp){  //求出每个节点的dfs序, dfs序对应的节点, 以及每个点所在链的顶端节点top[x] = tp, id[x] = ++tot, rk[tot] = x;if(son[x]) dfs2(son[x],tp);for(int v,i = head[x]; i; i = e[i].next)if((v = e[i].to)!=fa[x] && v!=son[x]) dfs2(v,v);
}inline void pushup(int x){ //基础的线段树向上区间合并t[x].sum = t[t[x].ls].sum+t[t[x].rs].sum;    //此题需要将sum和对mod取模t[x].maxn = max(t[t[x].ls].maxn,t[t[x].rs].maxn);
}void build(int l, int r, int x){ //基础建树,动态开点t[x].l = l, t[x].r = r, t[x].lazy = 0;if(l == r){t[x].sum = t[x].maxn = val[rk[l]]; return;}int mid = (l+r)>>1;t[x].ls = ++tot, t[x].rs = ++tot;build(l,mid,t[x].ls), build(mid+1,r,t[x].rs), pushup(x);
}inline int len(int x) { return t[x].r-t[x].l+1; }inline void pushdown(int x){ //基础的线段树标记下放if(t[x].lazy && t[x].l != t[x].r){int ls = t[x].ls, rs = t[x].rs, lz = t[x].lazy;(t[ls].lazy+=lz), (t[rs].lazy+=lz);(t[ls].sum+=lz*len(ls)), (t[rs].sum+=lz*len(rs));t[ls].maxn += lz, t[rs].maxn += lz;t[x].lazy = 0;}
}void update(int l, int r, int x, int c){ //基础的线段树更新if(t[x].l >= l && t[x].r <= r){(t[x].lazy += c), (t[x].sum += len(x)*c), t[x].maxn += c;return;}pushdown(x);int mid = (t[x].l+t[x].r)>>1;if(mid >= l) update(l,r,t[x].ls,c);if(mid < r) update(l,r,t[x].rs,c);pushup(x);
}int query(int l, int r, int x){     //基础的线段树查询if(t[x].l >= l && t[x].r <= r) return t[x].sum;pushdown(x);int mid = (t[x].l+t[x].r)>>1, tp = 0;if(mid >= l) tp += query(l,r,t[x].ls);if(mid < r) tp += query(l,r,t[x].rs);return tp;
}int query_max(int l, int r, int x){if(t[x].l >= l && t[x].r <= r) return t[x].maxn;pushdown(x);int mid = (t[x].l+t[x].r)>>1, tp = -1e17;if(mid >= l) tp = max(tp,query_max(l,r,t[x].ls));if(mid < r) tp = max(tp,query_max(l,r,t[x].rs));return tp;
}inline int sum_maxn(int x, int y){int ret = -1e17;while(top[x] != top[y]){ //让x与y到达同一条链if(d[top[x]] < d[top[y]]) swap(x,y); //找到更深的点ret = max(ret,query_max(id[top[x]],id[x],rt));// LOG1("ret",ret);x = fa[top[x]];}if(id[x] > id[y]) swap(x,y);// LOG2("id[x]",id[x],"id[y]",id[y]);return max(ret,query_max(id[x],id[y],rt));
}inline int sum(int x, int y){  //将区间分为多条链,对于每条链直接查询int ret = 0;while(top[x] != top[y]){ //让x与y到达同一条链if(d[top[x]] < d[top[y]]) swap(x,y); //找到更深的点ret += query(id[top[x]],id[x],rt);x = fa[top[x]];}if(id[x] > id[y]) swap(x,y);return (ret+query(id[x],id[y],rt));
}inline void updates(int x, int y, int c){  //区间加z, 将区间分为多条链while(top[x] != top[y]){if(d[top[x]] < d[top[y]]) swap(x,y);update(id[top[x]],id[x],rt,c);  //对于每条链直接修改x = fa[top[x]];}if(id[x] > id[y]) swap(x,y);update(id[x],id[y],rt,c);
}signed main()
{scanf("%lld",&n);init();rep(i,1,n-1){int x,y; scanf("%lld%lld",&x,&y);add(x,y), add(y,x);}rep(i,1,n) scanf("%lld",&val[i]);scanf("%lld",&m);root = 1;tot = 0, dfs1(root), dfs2(root, root);tot = 0, build(1,n,rt = ++tot);rep(i,1,m){char op[10]; scanf("%s",op);int x,y;if(op[1] == 'H'){// LOG1("op","1");scanf("%lld%lld",&x,&y);update(id[x],id[x],rt,y-val[x]);val[x] = y;}else if(op[1] == 'M'){// LOG1("op","2");scanf("%lld%lld",&x,&y);// LOG2("x",x,"y",y);printf("%lld\n",sum_maxn(x,y));}else if(op[1] == 'S'){// LOG1("op","3");scanf("%lld%lld",&x,&y);printf("%lld\n",sum(x,y));}}return 0;
}

【BZOJ 1036】树的统计【树链剖分模板】相关推荐

  1. [luogu P2590 ZJOI2008] 树的统计 (树链剖分)

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u ...

  2. 洛谷P3384 - 树链剖分(树链剖分模板题)

    题目链接 https://www.luogu.org/problemnew/show/P3384 [描述] 树链剖分模板题,记一下板子 #include<bits/stdc++.h> #d ...

  3. 洛谷——P2590 [ZJOI2008]树的统计(树链剖分模板练手)

    P2590 [ZJOI2008]树的统计 I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问 ...

  4. zjoi 2008 树的统计——树链剖分

    比较基础的一道树链剖分的题 大概还是得说说思路 树链剖分是将树剖成很多条链,比较常见的剖法是按儿子的size来剖分,剖分完后对于这课树的询问用线段树维护--比如求路径和的话--随着他们各自的链向上走, ...

  5. bzoj 4196 树链剖分 模板

    [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 2135  Solved: 1232 [Submit][Status] ...

  6. BZOJ1036[ZJOI2008]树的统计——树链剖分+线段树

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u ...

  7. 洛谷3384(树链剖分模板题)

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

  8. P3899 [湖南集训]更为厉害(线段树合并、长链剖分、二维数点)

    P3899 [湖南集训]更为厉害 若 deepb<deepa\text{deep}_b<\text{deep}_adeepb​<deepa​:c 在点 a 的子树中,根据乘法原理计算 ...

  9. [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分

    题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...

  10. 树链剖分——树链剖分模板

    原题 给定一棵树,树中包含 n 个节点(编号 1∼n),其中第 i 个节点的权值为 ai. 初始时,1 号节点为树的根节点. 现在要对该树进行 m 次操作,操作分为以下 4 种类型: 1 u v k, ...

最新文章

  1. [Wap]command和selectionList冲突的分析
  2. Serverless 工程实践 | 自建 Apache OpenWhisk 平台
  3. React 之 高阶组件的理解
  4. CodeForces - 1453E Dog Snacks(树形dp+贪心)
  5. ie的严苛,firefox的宽容
  6. 图论--网络流最大流问题
  7. JS生成动态表格并为每个单元格添加单击事件的方法
  8. 自学python从零开始学_新手学习python-从零开始学习
  9. linux 无法找到函数定义,找到定义Linux函数的位置
  10. java rt_java中rt包中源码了解
  11. 2345天气王怎么查看历史天气 2345天气王如何查看历史天气
  12. 广东机电职业技术学校计算机怎么样,广东机电职业技术学院宿舍怎么样 住宿条件好不好...
  13. C 小白的 thrift 环境搭建
  14. Android 学习资料汇总
  15. win7计算机图标删除,如何彻底删除Win7右下角操作中心的小白旗图标
  16. 神雕侠侣服务器维修时间,神雕侠侣什么时候更新_神雕侠侣更新维护了什么内容_快吧游戏...
  17. Gps测量两点之间的距离
  18. 函数模板和类模板详解
  19. 姓名+身份证号+人脸动态实名认证(百度)
  20. cocos3D 教程

热门文章

  1. Entity Framework 异常档案
  2. 你要金婚?还是金色软件?
  3. ASP.NET2.0下使用AJAX调用Webservice的方法
  4. RAID6磁盘阵列数据恢复
  5. 一个java文件里可以有多个类嘛?
  6. python快速整理excel_python批量处理excel文件数据
  7. html css 时钟,css3时钟
  8. linux 快速合并文本文件,Linux-Linux中高效合并文本文件的方法
  9. 鸿蒙系统手机能用几年,华为鸿蒙系统何时能用到手机上?任正非:短时间做不到 重建生态需要几年时间...
  10. len函数实例python_Python通过len函数返回对象长度