题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036

题意:一棵树,每个节点有一个权值。三种操作:(1)修改某个节点的权值;(2)输出某两个节点之间的权值之和;(3)输出某两个节点之间权值的最大值。

思路:(1)首先说明,在splay中记录一个father,表示当前节点的父节点。但是在这里,在一个树链中,father与在splay中的father的意义是一样的,也就是设v的father是u,那么u的左孩子或者右孩子必然有一个是v。但是,若v和u不在一个树链中,那么u表示v所在树链的最上面的顶点的父节点。也就是此时u的左孩子和右孩子都不是v,u和v属于两个树链;

(2)在一个树链中v的左孩子是在v上面的顶点,也就是在原树中这些点都是v的父节点以及祖宗节点;右孩子是v下面的顶点,也就是原树中v的孩子以及子孙节点。当然不管右孩子还是左孩子都是当前与v在一个树链中的;

(3)splay(x)将x旋转到x所在的树链的根,access(x)将x和root(这个root才是真正的树根)的边变为实边。在access(x)时,首先要断开x与其右孩子Xr的关联(在(4)中我们解释为什么要断开),并将Xr的father设为x,那么此时,Xr将成为一个树链的根;接着对于v的父节点u,因为要将u的右孩子变为v,所以之前u的右孩子(若有)Ur要与其断开并将Ur的father设为u,此时Ur将成为其所在树链的根;接着将u的右孩子设为v。一直向上直到root;

(4)每次计算(x,y)的最大或者和时,首先access(x)将x和root之间的边变为实边,然后access(y)此时返回值就是p=Lca(x,y)。想想为什么是这样?因为Lca(x,y)已经跟x在一个树链上了,因为我们已经access(x)了。现在从y开始向上找时,对于其father节点z,首先会splay(z)将z转到其所在树链的根节点,那么若z是Lca(x,y),那么z必然将成为树根,也就是root,那么其father节点为null。现在我们说明白了返回值为什么是 Lca(x,y)。接着p会与x断开,因为x在p的右孩子或者右孩子以下,p的右孩子将变成y所以断开了。此时若将splay(x),那么x就是p到x路径(不包含p)组成的树链的根,并且不会包含x以下的部分,在(3)中我们知道,x向上access时x与其右孩子已经断开。那么用x的sum以及p的val以及p的右孩子也就是y的sum就能计算出x到y的和。

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
long long w[],sum[],mx[];
int fa[],ch[][],st[];
int u[],v[],n,m,rev[],x,y;
void updata(int x){
int l=ch[x][],r=ch[x][];
sum[x]=w[x]+sum[l]+sum[r];
mx[x]=std::max(w[x],std::max(mx[l],mx[r]));
}
void pushdown(int x){
int l=ch[x][],r=ch[x][];
if (rev[x]){
rev[x]^=;
rev[l]^=;
rev[r]^=;
std::swap(ch[x][],ch[x][]);
}
}
bool pd(int x){
return ch[fa[x]][]!=x&&ch[fa[x]][]!=x;
}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
if (ch[y][]==x) l=;else l=;r=l^;
if (!pd(y)){
if (ch[z][]==y) ch[z][]=x;else ch[z][]=x;
}
fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
ch[y][l]=ch[x][r];ch[x][r]=y;
updata(y);updata(x);
}
void splay(int x){
int top=;st[++top]=x;
for (int i=x;!pd(i);i=fa[i]){
st[++top]=fa[i];
}
for (int i=top;i;i--)
pushdown(st[i]);
while (!pd(x)){
int y=fa[x],z=fa[y];
if (!pd(y)){
if (ch[y][]==x^ch[z][]==y) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){
for (int t=;x;t=x,x=fa[x]){
splay(x);
ch[x][]=t;
updata(x);
}
}
void makeroot(int x){
access(x);splay(x);rev[x]^=;
}
void link(int x,int y){
makeroot(x);
fa[x]=y;
}
int main(){
scanf("%d",&n);mx[]=-0x7fffffff;
for (int i=;i<n;i++){
scanf("%d%d",&u[i],&v[i]);
}
for (int i=;i<=n;i++){
scanf("%lld",&w[i]);
sum[i]=mx[i]=w[i];
}
for (int i=;i<n;i++){
link(u[i],v[i]);
}
scanf("%d",&m);
char s[];
for (int i=;i<=m;i++){
scanf("%s%d%d",s,&x,&y);
if (s[]=='H'){
splay(x);
w[x]=y;
updata(x);
}
else
if (s[]=='M'){
makeroot(x);
access(y);
splay(y);
printf("%lld\n",mx[y]);
}
else{
makeroot(x);
access(y);
splay(y);
printf("%lld\n",sum[y]);
}
} }

BZOJ 1036 [ZJOI2008]树的统计Count(动态树)的更多相关文章

  1. Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树)

    Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树) Description 一棵树上有n个节点,编号分别 ...

  2. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  3. bzoj 1036: [ZJOI2008]树的统计Count (树链剖分+线段树 点权)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 21194  Solved: 8589[Submit ...

  4. BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分)

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

  5. 1036: [ZJOI2008]树的统计Count (树链剖分)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3401  Solved: 1418[Submit] ...

  6. 1036: [ZJOI2008]树的统计Count(树链剖分)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 19830  Solved: 8067[Submit ...

  7. BZOJ 1036: [ZJOI2008]树的统计Count(树链剖分+单点更新+区间求和+区间求最大值)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 题意:略. 题解:树链剖分模版,注意一些细节即可. #include <ios ...

  8. BZOJ 1036: [ZJOI2008]树的统计Count 【树链剖分】

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

  9. BZOJ 1036 [ZJOI2008]树的统计Count 动态维护树上求和与求最大值 LCT板题

    模板,也可以用树链剖分+线段树做O(nlog2)O(nlog^2)O(nlog2) 用LCT做O(nlog)O(nlog)O(nlog)在乘上一个大于30的常数-然后LCT比树剖慢一倍- CODE # ...

  10. bzoj 1036: [ZJOI2008]树的统计Count (树链剖分)

    ps:这道题过的人真多啊 一道树剖的模板题 (好像还可以用lct做, 然而我并不会 代码如下 /**************************************************** ...

随机推荐

  1. Keil中LIB库的作用、生成与调用

    LIB库有什么用,一个简单的例子就是Silicon Labs为C8051F单片机USB提供的USBXpress LIB库了,如USB发送数据.接收数据等,都是通用性很强的函数,但因为保密的原因,这个函 ...

  2. Buffer Cache 原理

    在将数据块读入到SGA中,他们的缓冲区被放置在悬挂散列存储桶的链表中(散列链),这种内存结构由大量 子cache buffers chains锁存器(也称为散列锁存器或CBC锁存器)保护. Buffe ...

  3. Spark集群模式概述

    作者:foreyou出处:http://www.foreyou.net/2015/06/22/spark-cluster-mode-overview/声明:本文采用以下协议进行授权: 署名-非商用|C ...

  4. 15个提高编程技巧的JavaScript工具

    原文地址:http://www.imooc.com/wenda/detail/243523 JavaScript脚本库是一个预先用JavaScript语言写好的库,它方便了我们开发基于JavaScri ...

  5. phpcms:二、头部尾部包含

    1.index.html是默认的首页{template "content","header"}引入头部的模块{template "content&qu ...

  6. PyCharm常用设置

    pycharm,优秀的python开发工具 本文介绍一点python开发工具,pycharm的使用方式. 内容仅仅为最常用的几点,想要了解更多,请自行谷歌. 1.常用工具栏 唤出常用工具栏,View ...

  7. HBase二级索引的设计(案例讲解)

    摘要 最近做的一个项目涉及到了多条件的组合查询,数据存储用的是HBase,恰恰HBase对于这种场景的查询特别不给力,一般HBase的查询都是通过RowKey(要把多条件组合查询的字段都拼接在RowK ...

  8. javascript定时器:setTimeout与setInterval

    概述: setTimeout:在指定的延迟时间之后调用一个函数或者执行一个代码片段,只执行一次: setInterval:周期性地调用一个函数(function)或者执行一段代码,重复执行: 语法格式 ...

  9. oracle 同样数据删除(仅仅留一条)

    DELETE FROM reg_user t1 WHERE user_name='9527008' and rowid > ( SELECT min(rowid) FROM location t ...

  10. linux shell脚本连接oracle查询数据插入文件和日志文件中

    #!/bin/sh sqlplus "用户名/密码@数据库"<<EOF  或者只有一个库的 :sqlplus "用户名/密码"<<EOF ...