BZOJ 1036 树的统计-树链剖分
[ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 12904 Solved: 5191
[Submit][Status][Discuss]
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对
这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v
的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
Input
输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节
点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下
来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,以“CHANGE u t”或者
“QMAX u v”或者“QSUM u v”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;
中途操作中保证每个节点的权值w在-30000到30000之间。中途操作中保证每个节点的权值w在-30000
到30000之间。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
(代码摘自网络)
/* 关于各个数组和树链剖分的概念 记num[v]表示以v为根的子树的节点数, dep[v]表示v的深度(根深度为1), top[v]表示v所在的链的顶端节点, fa[v]表示v的父亲, son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子), tree[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置。 pre[v]是tree[v]的逆运算 数组名看得懂就OK 只要把这些东西求出来,就能用logn的时间完成原问题中的操作。 重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。 轻儿子:v的其它子节点。 重边:点v与其重儿子的连边。 轻边:点v与其轻儿子的连边。 重链:由重边连成的路径。 轻链:轻边。 剖分后的树有如下性质: 性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v]; 性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。 */ //该题目树中的点有权值而边没有 #include<iostream> #include<cstdio> using namespace std; ];//线段树 ];//边表 ],pre[],end[]]; ],data[],num[],top[],deep[]; int n,i,x,y,cnt,tot,Q; ]; int Max(int a,int b){return (a>b)?a:b;} void add(int u,int v){adj[++cnt].go=v;adj[cnt].next=end[u];end[u]=cnt;} void dfs1(int k,int fa,int d)//k是将要填充的节点,fa自然就是他的父亲,d就是深度 { //该函数计算了节点的重儿子,深度,以该节点为根的子树的节点数,节点的父亲 deep[k]=d;;/*以k为根的子树的节点数*/ for (int i=end[k]/*初始i为以k为起点的最后一条边的编号*/;i/*当i非0*/;i=adj[i].next/*访问i这条边,并将i赋值为i的下一条边*/) { int go=adj[i].go/*边i所指向的节点*/;if (go==fa)/*如果这条边指向他的父亲,则跳过*/ continue; dfs1(go,k,d+)/*递归,计算节点go,父亲是k,深度+1*/;num[k]+=num[go];/*累加以k为根的子树的节点数*/ if (!son[k]/*如果说son[k]还为0,说明还未计算*/||num[go]>num[son[k]]/*或者此次计算的子树节点超过了以前的重儿子的节点数,更新他*/) son[k]=go; //更新该节点的重儿子 } } void dfs2(int k,int Number)//Number表示k所在链的顶端节点 { //该函数计算了k所在链的顶端节点,节点k在线段树中的位置,线段树中某一编号对应的节点 top[k]=Number;tree[k]=++tot; //tree[i] 节点i在线段树中的编号 pre[tree[k]]=k; //pre[i] 线段树中点为i的对应的节点编号 if (!son[k]) return; //没有重儿子,说明是叶子节点,退出 dfs2(son[k],Number); //先递归重儿子,把他的孩子中的“重”部分也置为Number for (int i=end[k];i;i=adj[i].next)//遍历所有的边 { int go=adj[i].go;//边所连接到的顶点 if (go!=son[k]/*不是重儿子*/&&go!=f[k]/*不是父亲*/) dfs2(go,go/*一条新的链,顶端节点就是本身*/); //递归轻儿子 } } void build(int k,int l,int r)//构建线段树 { a[k].l=l;a[k].r=r; if (l==r) {a[k].sum=a[k].max=data[pre[l]];return;}//不能再分 ; build(k<<,l,mid);build((k<<)+,mid+,r);//建立完左右子树之后完成自身的建立 a[k].sum=a[k<<].sum+a[(k<<)+].sum; a[k].max=Max(a[k<<].max,a[(k<<)+].max); } void update(int k,int x,int jia)//jia是指更新时所加的变量 { if (a[k].l==a[k].r) { a[k].sum+=jia*(a[k].r-a[k].l+); a[k].max+=jia;return; } ; ,x,jia);)+,x,jia);//更新完左右子树后更新自己 a[k].sum=a[k<<].sum+a[(k<<)+].sum; a[k].max=Max(a[k<<].max,a[(k<<)+].max); } int ask_sum(int k,int x,int y)//此函数和下一个函数是单纯的线段树操作,要给x和y两个端点 { if (a[k].l>=x&&a[k].r<=y) return a[k].sum; ,o=; ,x,y);//包含左半部分 )+,x,y);//包含右半部分 return o; } int ask_max(int k,int x,int y)//这也是线段树,稍作改动即可 { if (a[k].l>=x&&a[k].r<=y) return a[k].max; ,o=-; ,x,y); )+,x,y)); return o; } int find_max(int x,int y) { ;//注意ans要置为-INF while (f1!=f2)//不是一个节点 { if(deep[f1]<deep[f2]) t=f1,f1=f2,f2=t,t=x,x=y,y=t; ans=Max(ans,ask_max(,tree[f1],tree[x]));//上升其中较深的节点,更新答案 x=f[f1];f1=top[x];//更新上升过一次的某个节点 } ans=Max(ans,(deep[x]>deep[y])?ask_max(,tree[y],tree[x]):ask_max(,tree[x],tree[y])); return ans; } int find_sum(int x,int y)//同上 { ; while (f1!=f2) { if (deep[f1]<deep[f2]) t=f1,f1=f2,f2=t,t=x,x=y,y=t; ans+=ask_sum(,tree[f1],tree[x]); x=f[f1];f1=top[x]; } ans+=(deep[x]>deep[y])?ask_sum(,tree[y],tree[x]):ask_sum(,tree[x],tree[y]); return ans; } int main() { scanf("%d",&n); ;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);//添加边 ;i<=n;i++) scanf("%d",&data[i]);//输入点的权值 dfs1(,,);dfs2(,);//预处理数组 build(,,n);//建立线段树 scanf("%d",&Q);//询问操作 while (Q) { Q--; scanf("%s%d%d",opt,&x,&y); ]==,tree[x],y-data[x]),data[x]=y;//change操作 ]=='M') printf("%d\n",find_max(x,y));//求最大值 else printf("%d\n",find_sum(x,y));//求和 } ; }
BZOJ 1036 树的统计-树链剖分的更多相关文章
- BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 23015 Solved: 9336[Submit ...
- 树的统计Count---树链剖分
NEFU专项训练十和十一——树链剖分 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t ...
- BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)
潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...
- BZOJ.3252.攻略(贪心 长链剖分/线段树)
题目链接 贪心,每次选价值最大的一条到根的链.比较显然(不选白不选). 考虑如何维护这个过程.一个点的价值选了就没有了,而它只会影响它子树里的点,可以用DFS序+线段树修改.而求最大值也可以用线段树. ...
- [ZJOI2008]树的统计——树链剖分
本题是一个树链剖分裸题,由于比较菜,老是RE,后来发现是因为使用了全局变量. /************************************************************ ...
- bzoj1036 树的统计 树链剖分模板
题意:给出树上任意两点,求路径上的值的和与最大值,带单点修改操作 树链剖分思路: 1.对树进行dfs求出点的深度和父亲节点,然后求出轻重儿子(重儿子就是点最多的那个子树,其余都是轻儿子),用一个son ...
- zjoi 2008 树的统计——树链剖分
比较基础的一道树链剖分的题 大概还是得说说思路 树链剖分是将树剖成很多条链,比较常见的剖法是按儿子的size来剖分,剖分完后对于这课树的询问用线段树维护——比如求路径和的话——随着他们各自的链向上走, ...
- BZOJ1036[ZJOI2008]树的统计——树链剖分+线段树
题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v ...
- [luogu P2590 ZJOI2008] 树的统计 (树链剖分)
题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u ...
随机推荐
- 进程间通信IPC之--共享内存
每个进程各自有不同的用户地址空间,任何一个进 程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲 区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲 ...
- C++开发者都应该使用的10个C++11特性
转载自http://blog.jobbole.com/44015/ 在C++11新标准中,语言本身和标准库都增加了很多新内容,本文只涉及了一些皮毛.不过我相信这些新特性当中有一些,应该成为所有C++开 ...
- Android的CursorLoader用法小结
工作内容集中到Contact模块,这个应用查询数据的地方很多,其使用了CursorLoader这个工具大大简化了代码复杂度.Android自3.0提供了Loader机制,当时google的API只是简 ...
- 我的wordpress插件总结
酷壳(CoolShell.cn)WordPress的插件 注意: 下面的这些插件的链接是其插件主页的链接,你可以在WordPress后台管理中添加插件时直接搜索安装就可以了. 插件不是越多越好.WP的 ...
- Builder模式(建造者模式)
在设计模式中对Builder模式的定义是用于构建复杂对象的一种模式,所构建的对象往往需要多步初始化或赋值才能完成.那么,在实际的开发过程中,我们哪些地方适合用到Builder模式呢?其中使用Build ...
- Linux使用笔记: 定制core dump文件的文件名
在开发过程中,当一个Linux程序异常退出时,我们可以通过core文件来分析它异常的详细原因.缺省情况下,Linux在程序异常时不产生core文件,要想让程序异常退出时产生core dump文件,需要 ...
- OAF_VO系列4 - Row Imp的分析(概念)
20150706 Created By BaoXinjian
- codeforces 336D. Vasily the Bear and Beautiful Strings 组合数学 dp
题意: 给出n,m,g,求好串的个数 0 <= n,m <= 10^5,n + m >= 1,0 <= g <= 1 好串的定义: 1.只由0,1组成,并且恰好有n个0, ...
- API 双方认证探讨
开放 api 已是大势所趋.而 api 这种东西有个特点就是覆水难收.一旦公开出去了,被大量用户使用,一旦修改,就会让广大用户都掉坑里.所以,api 在设计之初就要尽量考虑周全,并预留扩展可能. 目前 ...
- whois配置
$itemRules = array ( 'default' => array ( 'registry_domain_id' => 'Registry Domain ID:(.*?)', ...