BZOJ-4034- [HAOI2015]T2-树链剖分+线段树
来源:互联网 发布:程序员用外星人 编辑:程序博客网 时间:2024/04/26 21:01
http://www.lydsy.com/JudgeOnline/problem.php?id=4034
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
跑一遍树链剖分,记多一个dfs序
对操作1,单点修改
操作2,按dfs序区间修改
操作3,按剖分id查询(1,u)
//BZOJ4034#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;typedef long long ll;const int MAXN = 100000+50;struct Edge{ int to,next;} edge[MAXN*2];int head[MAXN],tot;int top[MAXN];//top[v]表示v所在的重链的顶端节点int fa[MAXN]; //父亲节点int deep[MAXN];//深度int num[MAXN];//num[v]表示以v为根的子树的节点数int p[MAXN];//p[v]表示v与其父亲节点的连边在线段树中的位置int fp[MAXN];//和p数组相反int son[MAXN];//重儿子int pos; int out[MAXN];//dfs序void init(){ tot = 0; memset(head,-1,sizeof(head)); pos = 0; memset(son,-1,sizeof(son));}void addedge(int u,int v){ edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++;}void dfs1(int u,int pre,int d) //第一遍dfs求出fa,deep,num,son{ deep[u] = d; fa[u] = pre; num[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(v != pre) { dfs1(v,u,d+1); num[u] += num[v]; if(son[u] == -1 || num[v] > num[son[u]]) son[u] = v; } }}void getpos(int u,int sp) //第二遍dfs求出top和p{ top[u] = sp; p[u] = ++pos; fp[p[u]] = u; if(son[u]!=-1) getpos(son[u],sp); for(int i = head[u] ; i != -1; i = edge[i].next) { int v = edge[i].to; if(v != son[u] && v != fa[u]) getpos(v,v); } out[u]=pos;}struct TREE{ ll sum[4*MAXN],add[4*MAXN] ; void build(int l,int r,int i) // 线段树的建立; { add[i]=0; //add[rt]=aa[++ok]; sum[i]=0; if(l==r) return; int mid=(l+r)>>1; build(l,mid,i<<1); build(mid+1,r,i<<1|1); } void pushDown(int i, int l, int r)//把i节点的延迟标记传递到左右儿子节点 { if(add[i] != 0) { int mid = (l + r) >> 1; add[i << 1] += add[i]; sum[i << 1] += (mid - l + 1) * add[i]; add[i << 1 | 1] += add[i]; sum[i << 1 | 1] += (r - mid) * add[i]; add[i] = 0; } } void update(int i, int l, int r, int ql,int qr, ll val) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val, { if(l > qr ||ql > r)//更新区间不在当前区间内 return ; if(l >=ql && r <=qr )//要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层 { sum[i]+=(r-l+1)* val; add[i]+=val; return ; } pushDown(i, l, r);//如果上面没reutrn 表示要往左右儿子区间查询,所以把延迟标记放下去 int mid = (l + r) >> 1; update(i << 1, l, mid, ql,qr, val); update(i << 1 | 1, mid + 1, r, ql,qr, val); sum[i] = (sum[i << 1] +sum[i << 1 | 1]); } ll query(int i, int l, int r, int ql, int qr) //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i { if(l > qr || ql > r) return 0; if(l >= ql && r <= qr) return sum[i]; pushDown(i, l, r);//同update int mid =( l + r) >> 1; return (query(i << 1, l, mid, ql, qr) +query(i << 1 | 1, mid + 1, r, ql, qr)); } ll findsum(int u,int v)//查询u->v链的sum { int f1=top[u],f2=top[v]; ll tmp=0; while(f1!=f2) { if (deep[f1]<deep[f2]) { swap(f1,f2); swap(u,v); } tmp+=(tmp,query(1,1,pos,p[f1],p[u])); u=fa[f1],f1=top[u]; } if (deep[u]>deep[v] ) swap(u,v); return (tmp+ query(1,1,pos,p[u],p[v])); //若val(u)是u到fu的边权,则用son[u] }};TREE tp;ll a[MAXN];int main(){ int n,m; init(); scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf("%lld",&a[i]); int u,v; for (int i=1; i<n; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs1(1,0,0); getpos(1,1); tp.build(1,pos,1); for (int i=1; i<=n; i++) tp.update(1,1,pos,p[i],p[i],a[i]); //son->fa的边权为e[i][2] int op; for (int i=1; i<=m; i++) { scanf("%d",&op); if (op==1) { scanf("%d%d",&u,&v); tp.update(1,1,pos,p[u],p[u],v); } else if (op==2) { scanf("%d%d",&u,&v); tp.update(1,1,pos,p[u],out[u],v); } else { scanf("%d",&u); printf("%lld\n",tp.findsum(1,u)); } } return 0;}
0 0
- BZOJ 4034 [HAOI2015]T2 树链剖分+线段树
- bzoj 4034 [HAOI2015]T2 树链剖分+线段树
- BZOJ 4034: [HAOI2015]T2|线段树|树链剖分
- BZOJ-4034- [HAOI2015]T2-树链剖分+线段树
- BZOJ 4034: [HAOI2015]T2(树链剖分,点权,线段树)
- 4034: [HAOI2015]T2 树链剖分+线段树
- BZOJ 4034 HAOI2015 T2 DFS序+线段树
- BZOJ 4034 [HAOI2015]T2 树链剖分
- [BZOJ 4034][HAOI2015]T2 [树链剖分]
- bzoj 4034: [HAOI2015]T2
- BZOJ 4034: [HAOI2015]T2
- BZOJ 4034 [HAOI2015]T2
- bzoj 4034 [HAOI2015]T2
- 【BZOJ4034】[HAOI2015]T2【树链剖分】【线段树】
- 4034: [HAOI2015]T2 (树链剖分)
- BZOJ 4034([HAOI2015]T2-树链剖分对子树处理)
- |BZOJ 4034|树链剖分|线段树|[HAOI2015]树上操作
- BZOJ[4034][HAOI2015]树上操作 树链剖分+线段树
- 堆栈和队列的实现
- [LeetCode]--295. Find Median from Data Stream(Max-Heap & Min-Heap)
- Android 内存泄漏总结(转)
- 从省赛回来之后到暑假集训和自己感受
- Delphi XE8移动应用开发中Android权限设置
- BZOJ-4034- [HAOI2015]T2-树链剖分+线段树
- 使用windeployqt.exe进行依赖查找打包
- hdu1233 还是畅通工程(MST最小生成树)
- LLVM和Clang背后的故事
- Android下拉刷新上拉加载控件,对所有View通用
- UVA11384 Help is needed for Dexter (递归、找规律)
- 2.文件系统
- oc的浅拷贝和深拷贝
- 归并排序 Mergesort