bzoj1036点权模板题
/*
HYSBZ1036
树上有1-n个结点,每个节点都有一个权值w
操作 CHANGE u t:把结点u的权值改为t
QMAX u v:询问从点u到v的路径上的节点的最大权值
QSUM u v:询问从点u到v的路径上的结点的权值和
从点u到点v路径上的结点包括u,v本身 */
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define MAXN 30010
using namespace std;
struct Edge{
int to, next;
}edge[MAXN*];
int head[MAXN], tot;
int top[MAXN];//重链顶端
int fa[MAXN];//父亲
int deep[MAXN];//深度,root=1
int num[MAXN];//子节点数
int p[MAXN];//v在线段树中的位置
int fp[MAXN];
int son[MAXN];//重儿子
int pos;
void init(){
tot = ;
memset(head, -, sizeof(head));
pos = ;
memset(son, -, sizeof(son));
}
void addedge(int u, int v){
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
//第一次dfs求fa,deep,son,num
void dfs1(int u, int pre, int d){
deep[u] = d;
fa[u] = pre;
num[u] = ;
for(int i = head[u]; i != -; i = edge[i].next){
int v = edge[i].to;
if (v != pre){
dfs1(v, u, d+);
num[u]+=num[v];
if (son[u]==-||num[v]>num[son[u]])
son[u] = v;
}
}
}
//第二次dfs求top,p,用pos记数
void getpos(int u, int sp){//sp表示重链顶端
top[u] = sp;
p[u] = pos++;
fp[p[u]] = u;
if (son[u]==-)
return;
getpos(son[u], sp);//先把重儿子查到底
for(int i = head[u]; i != -; i = edge[i].next){
int v = edge[i].to;//轻儿子
if (v != son[u] && v != fa[u])
getpos(v, v);
}
} //线段树部分
struct Node{
int l, r;
int sum;
int Max;
}segTree[MAXN*];
inline void push_up(int i){
segTree[i].sum = segTree[i<<].sum + segTree[i<<|].sum;
segTree[i].Max = max(segTree[i<<].Max, segTree[i<<|].Max);
}
int s[MAXN];
void build(int i, int l, int r){
segTree[i].l = l;
segTree[i].r = r; if (l==r){
segTree[i].sum = segTree[i].Max = s[fp[l]];
return;
} int mid = l+r >> ;
build(i<<, l, mid);
build(i<<|, mid+, r);
push_up(i);
}
//更新线段树的第k个值为val
void update(int i, int k, int val){
if(segTree[i].l == k && segTree[i].r == k){
segTree[i].Max = segTree[i].sum = val;
return;
}
int mid = segTree[i].l + segTree[i].r >> ;
if (k <= mid)
update(i<<, k, val);
else
update(i<<|, k, val);
push_up(i);//单点更新后要重新计算Max和Sum
}
//查询[l,r]区间的最大值
int queryMax(int i, int l, int r){
if(segTree[i].l == l && segTree[i].r == r)
return segTree[i].Max;
int mid = segTree[i].l+segTree[i].r >> ;
if (r <= mid)
return queryMax(i<<, l, r);
else if (l > mid)
return queryMax(i<<|, l, r);
else
return max(queryMax(i<<, l, mid), queryMax(i<<|, mid+, r));
}
//查询[l,r]区间的和
int querySum(int i, int l, int r){
if(segTree[i].l==l && segTree[i].r == r)
return segTree[i].sum;
int mid = segTree[i].l+segTree[i].r>>;
if(r <= mid)
return querySum(i<<,l,r);
else if(l > mid)
return querySum((i<<)|,l,r);
else
return querySum(i<<, l, mid)+querySum(i<<|, mid+, r);
}
//查询u->v路径上结点的最大权值
int findMax(int u, int v){
int f1 = top[u], f2 = top[v];
int tmp = -;
while(f1!=f2){//不在同一条重链上时
if(deep[f1]<deep[f2]){
swap(u, v);
swap(f1, f2);
}
tmp = max(tmp, queryMax(, p[f1], p[u]));//把这一条链上的求出来
u = fa[f1];
f1 = top[u];
}
if (deep[u]>deep[v])
swap(u,v);
return
max(tmp, queryMax(, p[u], p[v])); }
//查询u->v路径上结点的权值
int findSum(int u, int v){
int f1 = top[u];
int f2 = top[v];
int tmp = ;
while(f1 != f2){
if (deep[f1] < deep[f2]){
swap(f1, f2);
swap(u, v);
}
tmp += querySum(, p[f1], p[u]);
u = fa[f1];
f1 = top[u];
}
if(deep[u]>deep[v])
swap(u, v);
return tmp + querySum(, p[u], p[v]);
} int main(){
int n;
int q;
char op[];
int u, v;
while(scanf("%d", &n)==){
init();
for(int i = ; i < n; i++){
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
for(int i = ; i <= n; i++)
scanf("%d", &s[i]); dfs1(,,);
getpos(,);
build(, , pos-); scanf("%d", &q);
while(q--){
scanf("%s%d%d", op, &u, &v);
if (op[]=='C')
update(, p[u], v);//单点修改
else if (strcmp(op, "QMAX")==)
printf("%d\n", findMax(u, v));//查询u->v路径上点权的最大值
else
printf("%d\n", findSum(u, v));//查询路径上点权的和
}
}
return ;
}
bzoj1036点权模板题的更多相关文章
- EOJ Monthly 2018.8 D. Delivery Service-树上差分(边权/边覆盖)(边权转点权)(模板题)
D. Delivery Service 单测试点时限: 2.5 秒 内存限制: 512 MB EOJ Delivery Service Company handles a massive amount ...
- bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题
[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...
- 洛谷 P3128 [USACO15DEC]最大流Max Flow-树上差分(点权/点覆盖)(模板题)
因为徐州现场赛的G是树上差分+组合数学,但是比赛的时候没有写出来(自闭),背锅. 会差分数组但是不会树上差分,然后就学了一下. 看了一些东西之后,对树上差分写一点个人的理解: 首先要知道在树上,两点之 ...
- 【BZOJ1036】[ZJOI2008] 树的统计Count(一道可怕的模板题:树剖+线段树)
点此看题面 题解 这真的只是一道模板题:一个树链剖分套上一个线段树(令我窒息的组合). 既然是模板题,那就直接上代码吧. 代码 #include<bits/stdc++.h> #defin ...
- [置顶] 小白学习KM算法详细总结--附上模板题hdu2255
KM算法是基于匈牙利算法求最大或最小权值的完备匹配 关于KM不知道看了多久,每次都不能完全理解,今天花了很久的时间做个总结,归纳以及结合别人的总结给出自己的理解,希望自己以后来看能一目了然,也希望对刚 ...
- 【最大流ISAP】洛谷P3376模板题
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- POJ - 3264 线段树模板题 询问区间最大最小值
这是线段树的一个模板题,给出一串数字,然后询问区间的最大最小值. 这个其实很好办,只需把线段树的节点给出两个权值,一个是区间的最小值,一个是区间的最大值,初始化为负无穷和正无穷,然后通过不断地输入节点 ...
- HDU 3966 Aragorn's Story(模板题)【树链剖分】+【线段树】
<题目链接> 题目大意: 给定一颗带点权的树,进行两种操作,一是给定树上一段路径,对其上每个点的点权增加或者减少一个数,二是对某个编号点的点权进行查询. 解题分析: 树链剖分的模板题,还不 ...
- P1339 热浪 最短路径模板题
这么naive的题面一看就是最短路模板题~~~ ok.首先是floyd算法,tts,记得把k放在最外面就行了. #include <cstdio> #include <cstring ...
随机推荐
- ElasticSearch 之 dis_max tie_break的应用
1. 插入数据 PUT /my_index/my_type/ { "title": "Quick brown rabbits", "body" ...
- ElasticSearch 索引整体迁移方案
以下都是经过实战验证过的!!! [前提]使用相同的版本 ElasticSearch-5.5.1,只不过是在不同的服务器之间且重跑数据相对来说代价比较高,这种情况下就可以使用一下这种方式对索引整体迁移 ...
- 虚拟化技术之KVM
虚拟化技术之KVM 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是虚拟化 其实虚拟化技术已经不是一个新技术了,上个世纪六十年代IBM公司已经在使用,只不过后来(上个世纪八 ...
- Nginx核心配置文件常用参数详解
Nginx核心配置文件常用参数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 关于Nginx权威文档的话童鞋们可以参考Nginx官方文档介绍:http://nginx.org/ ...
- Golang的防坑小技巧
Golang的防坑小技巧 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 作为一名小白,在之前没有接触到编程的小伙伴,难免会踩到一些坑,比如说刚刚入门的时候你需要安装环境,学习Gol ...
- IoC之Ninject
一.Ninject安装 Ninject是一个轻量级的开源的DI容器,可以通过Nuget直接安装: 二.Ninject的简单使用 模型代码: //计算器接口 public interface ICalc ...
- ruby where用法
用法1 Subject.where(").order("name") 用法2 与find方法不同的是,where方法返回的结果不是数组而是ActiveRelation,这 ...
- #线程池pool 【参考】
参考链接 http://www.open-open.com/lib/view/open1415453575730.html 参考配置 http://www.cnblogs.com/linjiqin/a ...
- fastreport报表中出现十字线
问题描述:经常有十字线出现在报表中,出现在报表中不同的频带,在预览和运行时都会显示,不能点击和删除它. 解决方法:这是一个线控制,因太小而不能被渲染,所以fastreport使用十字线来表示其位置.通 ...
- JavaScript之DOM等级概述
这两日对DOM等级的理解不是太通透,就进Mozilla官网去看了一下,然后进行了首次的对技术文档的翻译工作,虽然官网也有中文解释,但我想,自己翻译出来时,已经有了原汁原味的理解了吧,这边是做此次翻译的 ...