【bzoj1036】[ZJOI2008]树的统计Count
题目描述
一棵树上有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本身
输入
输入的第一行为一个整数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之间。
输出
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
样例输入
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
样例输出
4
1
2
2
10
6
5
6
5
16
题解
树链剖分模板题,第一次码。。。
树链剖分就是把一棵树拆为一些链来处理,并用数据结构来维护。
通常的剖分方法是按照轻重链剖分,每次选取节点最多的子树继承重链,其余视作轻链,重新处理。
通常用线段树维护权值。
查询时,如果x和y在同一条链上,那么直接查询,否则一边将x和y往同一条链上靠,一边记录路径上的权值,然后查询。
代码应该不难理解。
#include <cstdio>
#include <algorithm>
using namespace std;
#define inf 0x3fffffff
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
int val[30005] , deep[30005] , si[30005] , fa[30005] , bl[30005] , pos[30005] , tot;
int head[30005] , to[60005] , next[60005] , cnt;
int maxn[120005] , sum[120005] , n;
char str[10];
void add(int x , int y)
{
to[++cnt] =y;
next[cnt] = head[x];
head[x] = cnt;
}
void dfs1(int x)
{
si[x] = 1;
int i , y;
for(i = head[x] ; i ; i = next[i])
{
y = to[i];
if(y != fa[x])
{
deep[y] = deep[x] + 1;
fa[y] = x;
dfs1(y);
si[x] += si[y];
}
}
}
void dfs2(int x , int c)
{
int k = 0 , i , y;
pos[x] = ++tot;
bl[x] = c;
for(i = head[x] ; i ; i = next[i])
{
y = to[i];
if(deep[y] > deep[x] && si[y] > si[k])
k = y;
}
if(k != 0)
{
dfs2(k , c);
for(i = head[x] ; i ; i = next[i])
{
y = to[i];
if(deep[y] > deep[x] && y != k)
dfs2(y , y);
}
}
}
void pushup(int x)
{
sum[x] = sum[x << 1] + sum[x << 1 | 1];
maxn[x] = max(maxn[x << 1] , maxn[x << 1 | 1]);
}
void update(int p , int c , int l , int r , int x)
{
if(l == r)
{
sum[x] = maxn[x] = c;
return;
}
int mid = (l + r) >> 1;
if(p <= mid)
update(p , c , lson);
else
update(p , c , rson);
pushup(x);
}
int querysum(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e)
return sum[x];
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid)
ans += querysum(b , e , lson);
if(e > mid)
ans += querysum(b , e , rson);
return ans;
}
int querymaxn(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e)
return maxn[x];
int mid = (l + r) >> 1 , ans = -inf;
if(b <= mid)
ans = max(ans , querymaxn(b , e , lson));
if(e > mid)
ans = max(ans , querymaxn(b , e , rson));
return ans;
}
int solvesum(int x , int y)
{
int ans = 0;
while(bl[x] != bl[y])
{
if(deep[bl[x]] < deep[bl[y]])
swap(x , y);
ans += querysum(pos[bl[x]] , pos[x] , 1 , n , 1);
x = fa[bl[x]];
}
if(pos[x] > pos[y])
swap(x , y);
ans += querysum(pos[x] , pos[y] , 1 , n , 1);
return ans;
}
int solvemaxn(int x , int y)
{
int ans = -inf;
while(bl[x] != bl[y])
{
if(deep[bl[x]] < deep[bl[y]])
swap(x , y);
ans = max(ans , querymaxn(pos[bl[x]] , pos[x] , 1 , n , 1));
x = fa[bl[x]];
}
if(pos[x] > pos[y])
swap(x , y);
ans = max(ans , querymaxn(pos[x] , pos[y] , 1 , n , 1));
return ans;
}
int main()
{
int i , x , y , q;
scanf("%d" , &n);
for(i = 1 ; i < n ; i ++ )
{
scanf("%d%d" , &x , &y);
add(x , y);
add(y , x);
}
for(i = 1 ; i <= n ; i ++ )
scanf("%d" , &val[i]);
dfs1(1);
dfs2(1 , 1);
for(i = 1 ; i <= n ; i ++ )
update(pos[i] , val[i] , 1 , n , 1);
scanf("%d" , &q);
while(q -- )
{
scanf("%s%d%d" , str , &x , &y);
switch(str[1])
{
case 'H': val[x] = y; update(pos[x] , y , 1 , n , 1); break;
case 'S': printf("%d\n" , solvesum(x , y)); break;
default: printf("%d\n" , solvemaxn(x , y));
}
}
return 0;
}
【bzoj1036】[ZJOI2008]树的统计Count的更多相关文章
- [BZOJ1036][ZJOI2008]树的统计Count 解题报告|树链剖分
树链剖分 简单来说就是数据结构在树上的应用.常用的为线段树splay等.(可现在splay还不会敲囧) 重链剖分: 将树上的边分成轻链和重链. 重边为每个节点到它子树最大的儿子的边,其余为轻边. 设( ...
- bzoj1036 [ZJOI2008]树的统计Count
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MB Submit: 12646 Solved: 5085 [Subm ...
- bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题
[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...
- bzoj千题计划124:bzoj1036: [ZJOI2008]树的统计Count
http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分板子题 #include<cstdio> #include<iost ...
- BZOJ1036 [ZJOI2008]树的统计Count 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1036 题意概括 一个树,每个节点有一个权值.3种操作. 1:修改某一个节点的权值. 2:询问某两个 ...
- 【lct】bzoj1036 [ZJOI2008]树的统计Count
题意:给你一棵树,点带权,支持三种操作:单点修改:询问链上和:询问链上max. 这里的Query操作用了与上一题不太一样的做法(上一题用那种做法,因为在边带权的情况下换根太困难啦): 先ChangeR ...
- BZOJ1036[ZJOI2008]树的统计Count 题解
题目大意: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.有一些操作:1.把结点u的权值改为t:2.询问从点u到点v的路径上的节点的最大权值 3.询问从点u到点v的路径上的节点的权值和 ...
- bzoj1036 zjoi2008 树的统计 count
填坑= =第一道裸树剖 #include<cstdio> #include<algorithm> #include<cstring> #include<cst ...
- [BZOJ1036] [ZJOI2008] 树的统计Count (LCT)
Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...
- bzoj1036 [ZJOI2008]树的统计Count(树链剖分)
Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. Q ...
随机推荐
- Newton-Raphson算法简介及其R实现
本文简要介绍了Newton-Raphson方法及其R语言实现并给出几道练习题供参考使用. 下载PDF格式文档(Academia.edu) Newton-Raphson Method Let $f(x) ...
- Beta版本冲刺第四天 12.10
一.站立式会议照片: 二.项目燃尽图: Android端 后台 三.项目进展: 成 员 昨天完成任务 今天完成任务 明天要做任务 问题困难 心得体会 胡泽善 日期合理性的判断,一个是用户反馈的查看 管 ...
- ELKstack搭建
开源实时日志分析ELK平台部署 官网地址:https://www.elastic.co/products 介绍: Elasticsearch是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现 ...
- uC/OS-II核心(Os_core)块
/*************************************************************************************************** ...
- redis主从复制操作
1. 33.10服务器上 启动三个redis bin/redis-server etc/redis.conf bin/redis-server etc/6380conf bin/redis-serve ...
- Java反射机制<1>
如果要通过一个对象找到一个类的名称,此时就需要用到反射机制(反射技术是用来做框架的,一般情况下Java私有对象不能被访问,但是暴力反射可以访问私有对象). 任何一个类如果没有明确地声明继承自哪个父类的 ...
- Winsock 入门 判读主机字节序 示例
#include <stdio.h> union endian_u { /*最大成员的长度就是联合成员的长度.联合可以在定义时直接进行初始化,但这个初始化必须是联合第一个成员的类型,所以把 ...
- texlive2015+texstudio
编译器 texlive2015 编辑器 texstudio
- 后台程序员的HTTP缓存
1.后端程序员只需要关注请求头: if-None-Match //上一次response头中的ETag的值. 响应头: Etag //是URL的Entity Tag,用于标示URL对象是否改变,区分不 ...
- input 获取当前id,name
<input name=" src="toright.png" value="mp3"> <script language=&quo ...