Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. 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之间。

Output

  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

Sample Output

4
1
2
2
10
6
5
6
5
16

正解:树链剖分+线段树

解题报告:

  维护树上一条路径上的结点权值最大值或和

  没什么好说的,链剖裸题。先树链剖分再根据访问次序建立线段树,用线段树动态维护。

  模板题练手。

 //It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = ;
const int inf = (<<);
int n;
int total,ecnt;
int U,VV;
int a[MAXN];
int id[MAXN],pre[MAXN];
int top[MAXN],siz[MAXN],zhongerzi[MAXN],father[MAXN],deep[MAXN];
int next[MAXN*],to[MAXN*],first[MAXN];
char ch[]; struct node{
int l,r;
int _max;int _sum;
}jump[MAXN*]; void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; } int getint()
{
int w=,q=;
char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar();
if (c=='-') q=, c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar();
return q ? -w : w;
} void build(int root,int l,int r){
jump[root].l=l;jump[root].r=r;
if(jump[root].l==jump[root].r) {
jump[root]._sum=jump[root]._max=a[ pre[l] ];
return ;
}
int lc=root*,rc=root*+;
int mid=l+(r-l)/;
build(lc,l,mid); build(rc,mid+,r);
jump[root]._sum=jump[lc]._sum+jump[rc]._sum;
jump[root]._max=max(jump[lc]._max,jump[rc]._max);
} void dfs1(int u,int fa){
siz[u]=;
for(int i=first[u];i;i=next[i]) {
int v=to[i];
if(v!=fa) {
father[v]=u;
deep[v]=deep[u]+;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[ zhongerzi[u] ]) zhongerzi[u]=v;
}
}
} void dfs2(int u,int fa){
id[u]=++total; pre[total]=u;
if(zhongerzi[u]) top[zhongerzi[u]]=top[u],dfs2(zhongerzi[u],u);
for(int i=first[u];i;i=next[i]) {
int v=to[i];
if(v==fa || v==zhongerzi[u]) continue;
top[v]=v;
dfs2(v,u);
}
} int query_sum(int root,int x,int y){
if(jump[root].l>=x && jump[root].r<=y) return jump[root]._sum;
int da=;
int mid=jump[root].l+(jump[root].r-jump[root].l)/;
int lc=root*,rc=root*+;
if(x<=mid) da+=query_sum(lc,x,y);
if(y>mid) da+=query_sum(rc,x,y);
return da;
} int query_max(int root,int x,int y){
if(jump[root].l>=x && jump[root].r<=y) return jump[root]._max;
int da=-inf;
int mid=jump[root].l+(jump[root].r-jump[root].l)/;
int lc=root*,rc=root*+;
if(x<=mid) da=max(da,query_max(lc,x,y));
if(y>mid) da=max(da,query_max(rc,x,y));
return da;
} int find_max(int x,int y){
int f1=top[x],f2=top[y];
int daan=-inf;
while(f1!=f2){
if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y);
daan=max(daan,query_max(,id[f1],id[x]));
x=father[f1];
f1=top[x];
}
if(deep[x]<deep[y]) swap(x,y);
daan=max(daan,query_max(,id[y],id[x]));
return daan;
} int find_sum(int x,int y){
int f1=top[x],f2=top[y];
int daan=;
while(f1!=f2){
if(deep[f1]<deep[f2]) swap(f1,f2),swap(x,y);
daan+=query_sum(,id[f1],id[x]);
x=father[f1]; f1=top[x];
}
if(deep[x]<deep[y]) swap(x,y);
daan+=query_sum(,id[y],id[x]);
return daan;
} void update(int root,int o,int add){
if(jump[root].l==jump[root].r){
jump[root]._sum+=add;
jump[root]._max+=add;return ;
}
int lc=root*,rc=root*+;
int mid=jump[root].l+(jump[root].r-jump[root].l)/;
if(o<=mid) update(lc,o,add); else update(rc,o,add);
jump[root]._sum=jump[lc]._sum+jump[rc]._sum;
jump[root]._max=max(jump[lc]._max,jump[rc]._max);
} int main()
{
n=getint();
int x,y;
for(int i=;i<n;i++){
x=getint();y=getint();
next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y;
next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x;
} deep[]=; dfs1(,);
top[]=; dfs2(,); for(int i=;i<=n;i++) a[i]=getint();
build(,,n);
int Q=getint(); for(int i=;i<=Q;i++){
scanf("%s",ch);
if(ch[]=='M'){
printf("%d\n",find_max(x,y));
}
else if(ch[]=='S'){
x=getint();y=getint();
printf("%d\n",find_sum(x,y));
}
else{
U=getint();VV=getint();
update(,id[U],VV-a[U]);a[U]=VV;
}
}
return ;
}

BZOJ1036 树的统计的更多相关文章

  1. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)

    潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...

  2. bzoj1036 树的统计(树链剖分+线段树)

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

  3. bzoj1036 树的统计 树链剖分模板

    题意:给出树上任意两点,求路径上的值的和与最大值,带单点修改操作 树链剖分思路: 1.对树进行dfs求出点的深度和父亲节点,然后求出轻重儿子(重儿子就是点最多的那个子树,其余都是轻儿子),用一个son ...

  4. 树剖裸题——BZOJ1036 树的统计

    #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #defi ...

  5. BZOJ1036——树的统计count

    1.题目大意:给你一棵树,有三种操作 1>qmax,询问u到v中间点权的最大值 2>qsum,询问u到v中间点权和 3>change,把u这个节点的权值改为v 2.分析:树链剖分的裸 ...

  6. p2590&bzoj1036 树的统计

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

  7. bzoj1036 树的统计Count

    第一次写链剖,于是挑了个简单的裸题写. 以下几点要注意: 1.链剖中的height是从根到该店经过的轻边个数 2.分清num与sum..... #include<cstdio> #incl ...

  8. 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

    [BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...

  9. [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分

    树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...

随机推荐

  1. Unity 2D Sprite Lighting

    2D游戏中也可以使用灯光?这真是一个好消息,接下来,我将为大家写一下教程 操作步骤 1.创建一个Materilas,修改Shader为 2.创建一个Sprite(使用黑色的图片) 3.创建一个Poin ...

  2. eclipse点击一个变量使相同名称变量高亮显示的方法

    preferences->java->Editor->Mark Occurences 选择最上的复选框,下面的就有很多了. 其中的Local variables就是变量的高亮显示.

  3. shell+curl监控网站页面(域名访问状态),并利用sedemail发送邮件

    应领导要求,对公司几个主要站点的域名访问情况进行监控.下面分享一个监控脚本,并利用sendemail进行邮件发送. 监控脚本如下:下面是写了一个多线程的网站状态检测脚本,直接从文件中读出站点地址,然后 ...

  4. 大话redis/memcache缓存

    通常情况下,随着业务量增加,对后端数据库的访问压力也会随之加大.当数据库访问压力渐渐增大时,除了升级数据库配置提高数据库本身的抗压能力外,我们也可以采用在应用服务器与数据库服务器之间架设数据库缓存服务 ...

  5. Wireshark命令行工具tshark

    Wireshark命令行工具tshark 1.目的 写这篇博客的目的主要是为了方便查阅,使用wireshark可以分析数据包,可以通过编辑过滤表达式来达到对数据的分析:但我的需求是,怎么样把Data部 ...

  6. [shell]. 点的含义

    . 的含义 当前目录 隐藏文件 任意一个字符 生效配置文件

  7. JS面向对象的几种写法

    JS 中,面向对象有几种写法.归纳下,大概有下面这几种:工厂模式,构造函数模式,原型模式,构造函数与原型模式的混合使用,原型链继承,借用构造函数继承. 一.工厂模式 function person ( ...

  8. php基础32:正则匹配-修饰符

    <?php //正则表达式--修饰符一般放在//的外面 //1. i 表示不区分大小写 $model = "/php/"; $string = "php" ...

  9. Html5实践之EventSource

    最近尝试了一下服务器端的推送,之前的做法都是客户端轮询,定时向服务器发送请求.但这造成了我的一些困扰: 1:轮询是由客户端发起的,那么在服务端就不能判别我要推送的内容是否已经过期,因为我很难判断某个信 ...

  10. TinyFrame框架中的UOW使用方式纠正

    我自己的框架中,UOW是可以通过反射提取具体的Repository的,也可以调用Commit方法. 但是正确的应用方式应该是: Using(var uow = new UnitOfWork()) { ...