传送门

题意:

给你一个有nnn个顶点的树,树上的每一个点都有一个点权,现在有333种操作:

  • IuvkI~ u~v~kI u v k,代表将结点uuu到结点vvv的最近的路径上的所有点的点权增加kkk
  • DuvkD~ u~v~kD u v k ,代表将结点uuu到结点vvv的最近的路径上的所有点的点权减少kkk
  • QuQ~ uQ u,代表求出结点uuu的点权。

题目分析:

树链剖分的模板题。

倘若只有操作111和操作222,则我们只需要用树上差分用O(n+m)\mathcal{O}(n+m)O(n+m)的时间复杂度完成操作。

但是,现在这个问题中,因此操作333的存在,使得用树上差分去做的话时间复杂度将会不优。

因此我们可以考虑采用树链剖分。

我们将树上的重链剖分出来之后,获取出他们的dfsdfsdfs序,并用数据结构(线段树/树状数组)去维护区间的和即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=50005;
struct Node{int to,next;
}q[100005];
struct ST{int sum,len,lazy;
}tr[maxn<<2];
int head[maxn],cnt=0,tot=0,f[maxn],dis[maxn],son[maxn],size[maxn],top[maxn];
int id[maxn],rk[maxn],v[maxn];
void add_edge(int from,int to){q[cnt].to=to;q[cnt].next=head[from];head[from]=cnt++;
}
void dfs1(int x){size[x]=1,dis[x]=dis[f[x]]+1;for(int i=head[x];i!=-1;i=q[i].next){int to=q[i].to;if(to==f[x]) continue;f[to]=x;dfs1(to);size[x]+=size[to];if(size[to]>size[son[x]]){son[x]=to;}}
}
void dfs2(int x,int t){top[x]=t;id[x]=++tot;rk[tot]=x;if(son[x]) dfs2(son[x],t);for(int i=head[x];i!=-1;i=q[i].next){int to=q[i].to;if(to==son[x]||to==f[x]) continue;dfs2(to,to);}
}
void push_up(int rt){tr[rt].sum=tr[rt<<1].sum+tr[rt<<1|1].sum;
}
void push_down(int rt){if(tr[rt].lazy){tr[rt<<1].sum+=1ll*tr[rt].lazy*tr[rt<<1].len;tr[rt<<1|1].sum+=1ll*tr[rt].lazy*tr[rt<<1|1].len;tr[rt<<1].lazy=tr[rt<<1].lazy+tr[rt].lazy;tr[rt<<1|1].lazy=tr[rt<<1|1].lazy+tr[rt].lazy;tr[rt].lazy=0;}
}
void build(int l,int r,int rt){tr[rt].lazy=0;tr[rt].len=r-l+1;if(l==r){tr[rt].sum=v[rk[l]];return ;}int mid=(l+r)>>1;build(l,mid,rt<<1);build(mid+1,r,rt<<1|1);push_up(rt);
}
void update(int L,int R,int l,int r,int rt,int k){if(L<=l&&R>=r){tr[rt].lazy=tr[rt].lazy+k;tr[rt].sum=tr[rt].sum+tr[rt].len*k*1l;return ;}push_down(rt);int mid=(l+r)>>1;if(L<=mid) update(L,R,l,mid,rt<<1,k);if(R>mid) update(L,R,mid+1,r,rt<<1|1,k);push_up(rt);
}
int query(int L,int R,int l,int r,int rt){if(L<=l&&R>=r){return tr[rt].sum;}push_down(rt);int mid=(l+r)>>1;int res=0;if(L<=mid) res+=query(L,R,l,mid,rt<<1);if(R>mid) res+=query(L,R,mid+1,r,rt<<1|1);return res;
}
int cal(int x,int y){int res=0;while(top[x]!=top[y]){if(dis[top[x]]<dis[top[y]]) swap(x,y);res+=query(id[top[x]],id[x],1,tot,1);x=f[top[x]];}if(id[x]>id[y]) swap(x,y);res+=query(id[x],id[y],1,tot,1);return res;
}
void UPDATE(int x,int y,int c){while(top[x]!=top[y]){if(dis[top[x]]<dis[top[y]]) swap(x,y);update(id[top[x]],id[x],1,tot,1,c);x=f[top[x]];}if(id[x]>id[y]) swap(x,y);update(id[x],id[y],1,tot,1,c);
}
int main()
{int n,m,t;while(~scanf("%d%d%d",&n,&m,&t)){memset(head,-1,sizeof(head));memset(dis,0,sizeof(dis));memset(son,0,sizeof(son));tot=0;cnt=0;for(int i=1;i<=n;i++) scanf("%d",&v[i]);for(int i=1;i<n;i++){int from,to;scanf("%d%d",&from,&to);add_edge(from,to);add_edge(to,from);}dfs1(1);dfs2(1,1);build(1,tot,1);while(t--){int x,y,z;char op[2];scanf("%s",op);if(op[0]=='I'){scanf("%d%d%d",&x,&y,&z);UPDATE(x,y,z);}if(op[0]=='D'){scanf("%d%d%d",&x,&y,&z);z=-z;UPDATE(x,y,z);}if(op[0]=='Q'){scanf("%d",&x);int res=query(id[x],id[x],1,tot,1);printf("%d\n",res);}}}return 0;
}

HDU 3966(树链剖分)相关推荐

  1. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  2. hdu 3966( 树链剖分+点权更新)

    题意:给一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路径上的所有点权值加上K D C1 C2 K:把C1与C2的路径上的所有点权值减去K Q C:查询节点编号为C ...

  3. HDU 3966 树链剖分后线段树维护

    题意: 一棵树, 操作1.$path(a,b)$之间的点权$+k$ 操作2.单点查询 题解: 树链剖分即可,注意代码细节,双向映射 主要是记录一下板子 #include <string.h> ...

  4. hdu 5274(树链剖分)

    解题思路:这道题据说是树链剖分,所以也学习了一下. http://blog.sina.com.cn/s/blog_7a1746820100wp67.html 不同的是这里是点权值,我按照相似的处理方式 ...

  5. HDU 5405 (树链剖分+线段树)

    Problem Sometimes Naive 题目大意 给你一棵n个节点的树,有点权. 要求支持两种操作: 操作1:更改某个节点的权值. 操作2:给定u,v, 求 Σw[i][j]   i , j ...

  6. hdu 5052 树链剖分+线段树+区间合并

    各种裸,但合在一起好恶心... 因为路径是有向的,所以要维护区间里向两个方向走的最大收益和区间里的最大最小值,要用到区间合并的线段树 #include <iostream> #includ ...

  7. HDU - 3966 Aragorn's Story(树链剖分)

    题目传送门:HDU - 3966 Aragorn's Story 题目大意: 存在一个树,树上每个节点为一个阵营,阵营中存在敌人,现在要进行以下操作 I  C1  C2  K :将阵营C1到阵营C2路 ...

  8. HDU 3966 POJ 3237 HYSBZ 2243 HRBUST 2064 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  9. SPOJ- QTREE+HDU 3966(树链剖分裸题

    题目:维护一个树,支持修改边长,查询任意两点间距离. 思路:学习了一下树链剖分,还是看了一阵子才看懂的(大概两个多小时orz...)其实总的来说并不是很难,主要是数组比较多,然后看的那篇博客大概是为了 ...

  10. HDU 3966 Aragorn's Story (树链剖分+线段树)

    题意:给你一棵树,然后有三种操作 I L R K: 把L与R的路径上的所有点权值加上K D L R K:把L与R的路径上的所有点权值减去K Q X:查询节点编号为X的权值 思路:树链剖分裸题(我还没有 ...

最新文章

  1. Behave step matcher
  2. js之数组,对象,类数组对象
  3. configure: error: mcrypt.h not found. Please reins
  4. 操作系统和Web服务器那点事儿
  5. 奢侈品级别的广告位,到底要不要继续砸钱?
  6. 互联网人的恶梦是加班?不,是饥荒!
  7. java 读取csv_Java读取CSV的常用方法 | 学步园
  8. Python 小白从零开始 PyQt5 项目实战(7)折叠侧边栏的实现
  9. 工具使用-----Jmeter的基础用法
  10. 2020受欢迎的20个JavaScript 库
  11. linux下svn命令
  12. 给 IDEA 换个酷炫的主题吧,这个有点哇塞啊!
  13. 以太坊虚拟机 EVM(2)Solidity运行原理
  14. 官方授权正版老牌截图工具 Ashampoo Snap 12 中文网站 屏幕截图与视频录制工具
  15. hive 如何将数组转成字符串_HIve字符串函数
  16. FeedBurner 被阻尼,Feed 托管转到 FeedSky
  17. 一款让人耳目一新的事件驱动型RTOS
  18. 从零开始搭建SpringBoot项目(一)——开发环境搭建(图文详细)
  19. 习题9-2(免费糖果)【深搜dfs】+【记忆化搜索】
  20. SWFObject 2.0官方文档

热门文章

  1. RestClient 访问elasticsearch
  2. 电商销售分析之制作销售看板
  3. Keys配置及使用说明
  4. 5.android系统裁剪
  5. 双色OLED屏图片点阵转换工具(OledTools)
  6. 最小采样频率计算公式_音频文件大小计算公式-好文转载
  7. 个人工作资源(不断更新)
  8. MacBook Pro打开前置摄像头
  9. FPGA零基础学习:理解数字信号和模拟信号
  10. 开源OLAP系统对比