BZOJ 3531(树链剖分+线段树)
Problem 旅行 (BZOJ 3531)
题目大意
给定一颗树,树上的每个点有两个权值(x,y)。
要求维护4种操作:
操作1:更改某个点的权值x。
操作2:更改某个点的权值y。
操作3:求a-->b路径上所有x属性与a,b相同的点y属性的和。
操作4:求a-->b路径上所有x属性与a,b相同的点y属性的最大值。
N,Q ,x <= 10^5 , y <= 10^4
解题分析
由于x属性的范围较大,无法直接统计。
考虑每次修改为单点修改,询问时只对相同x属性的询问。
因此,对于每个x属性开一棵线段树,询问时直接在相对应的线段树内查询。
开这么多棵线段树的话,就要动态开点,某个点的左右儿子的编号不是当前点编号的2倍或2倍加1。
参考程序
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std; #define N 10000008
#define V 100008
#define E 200008
#define lson l,m,ls[rt]
#define rson m+1,r,rs[rt] int n,Q,cnt;
int size[V],dep[V],fa[V],son[V],w[V],top[V],rk[V],root[V];
int a[V],c[V]; struct line{
int u,v,nt;
}eg[E];
int lt[V],sum; void adt(int u,int v){
eg[++sum].u=u; eg[sum].v=v; eg[sum].nt=lt[u]; lt[u]=sum;
}
void add(int u,int v){
adt(u,v); adt(v,u);
} struct segment_tree{
int sum[N],mx[N],ls[N],rs[N];
void pushup(int rt){
sum[rt]=sum[ls[rt]]+sum[rs[rt]];
mx[rt]=max(mx[ls[rt]],mx[rs[rt]]);
}
void update(int x,int val,int l,int r,int &rt){ //============ 这个 & 符号用得还是蛮精髓的 ====================
if (rt==) rt=++cnt;
if (l==r){
sum[rt]=val;
mx[rt]=val;
return;
}
int m=(l+r)/;
if (x <= m) update(x,val,lson);
if (m < x) update(x,val,rson);
pushup(rt);
}
int query_sum(int L,int R,int l,int r,int rt){
if (L<=l && r<=R){
return sum[rt];
}
int m=(l+r)/;
int res=;
if (L <= m) res+=query_sum(L,R,lson);
if (m < R) res+=query_sum(L,R,rson);
return res;
}
int query_max(int L,int R,int l,int r,int rt){
if (L<=l && r<=R){
return mx[rt];
}
int m=(l+r)/;
int res=;
if (L <= m) res=max(res,query_max(L,R,lson));
if (m < R) res=max(res,query_max(L,R,rson));
return res;
}
}T; void dfs_1(int u){
dep[u]=dep[fa[u]]+; size[u]=; son[u]=;
for (int i=lt[u];i;i=eg[i].nt){
int v=eg[i].v;
if (v==fa[u]) continue;
fa[v]=u;
dfs_1(v);
size[u]+=size[v];
if (size[v]>size[son[u]]) son[u]=v;
}
}
void dfs_2(int u,int tp){
top[u]=tp; w[u]=++cnt; rk[cnt]=u;
if (son[u]) dfs_2(son[u],tp);
for (int i=lt[u];i;i=eg[i].nt){
int v=eg[i].v;
if (v==fa[u] || v==son[u]) continue;
dfs_2(v,v);
}
}
void solve_sum(int x,int y){
int res=,cl=c[x];
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
res+=T.query_sum(w[top[x]],w[x],,n,root[cl]);
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
res+=T.query_sum(w[x],w[y],,n,root[cl]);
printf("%d\n",res);
}
void solve_max(int x,int y){
int res=,cl=c[x];
while (top[x]!=top[y]){
if (dep[top[x]]<dep[top[y]]) swap(x,y);
res=max(res,T.query_max(w[top[x]],w[x],,n,root[cl]));
x=fa[top[x]];
}
if (dep[x]>dep[y]) swap(x,y);
res=max(res,T.query_max(w[x],w[y],,n,root[cl]));
printf("%d\n",res);
} int main(){
memset(lt,,sizeof(lt)); sum=;
scanf("%d %d",&n,&Q);
for (int i=;i<=n;i++) scanf("%d %d",&a[i],&c[i]);
for (int i=;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
}
dfs_1();
dfs_2(,);
cnt=;
for (int i=;i<=n;i++) T.update(w[i],a[i],,n,root[c[i]]);
while (Q--){
char x[];
int y,z;
scanf("%s%d%d",x,&y,&z);
if (strcmp(x,"CC")==){
T.update(w[y],,,n,root[c[y]]);
c[y]=z;
T.update(w[y],a[y],,n,root[c[y]]);
}
if (strcmp(x,"CW")==){
a[y]=z; // ====================== debug ============//
T.update(w[y],z,,n,root[c[y]]);
}
if (strcmp(x,"QS")==){
solve_sum(y,z);
}
if (strcmp(x,"QM")==){
solve_max(y,z);
}
}
}
BZOJ 3531(树链剖分+线段树)的更多相关文章
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- bzoj 2157: 旅游【树链剖分+线段树】
裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
随机推荐
- 18. 4Sum -- 找到数组中和为target的4个数
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...
- 镜像渐变-radio-gradient
2013年11月15日13:08:37 <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"&g ...
- juery 选择器 选择多个元素
使用,号: $("#goodSource,#mailState") 选择了id为goodSource或者mailState的元素,当两者之间有任何一个有改变时,将会触发该操作. / ...
- [转]使用Java Mission Control进行内存分配分析
jdk7u40自带了一个非常好用的工具,就是Java Mission Control.JRockit Misson Control用户应该会对mission control的很多功能十分熟悉,JRoc ...
- 利用VBoxManage对虚拟机格式vdi、vmdk、vhd进行互转
虚拟机顾名思义就是虚拟出来的机器(virtual machine),虚拟化技术也是时下IT界最热门的技术,因其能更加有效利用硬件资源,整合IT应用,降低TCO,节能环保等,说白了就是一台硬件上够强 ...
- linux在shell date获取时间的相关操作
获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今天之前或者往后的日期,这时可以使用 ...
- 53个要点提高PHP编程效率
1.如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍. 2.$row[’id’] 的速度是$row[id]的7倍.3.echo 比 print 快,并且使用echo ...
- oracle之to_char,to_date用法
[转载自]http://www.jb51.net/article/45591.htm 这篇文章主要介绍了oracle中to_date详细用法示例,包括期和字符转换函数用法.字符串和时间互转.求某天是星 ...
- 迭代输出Map和List<Map<String,Object>>的方法
一.Map<String,Object> String:key的类型 Object:value的类型,value可能是String,或者int类型,什么类型都可以 对于Map接口来说,本身 ...
- C#winform省市县联动,以及有的县是空值时显示异常的处理
一.如下comboBox1.comboBox2.comboBox3,原来这三个都是空的, 将数据库中的省份传递到comboBox1中 我的数据库有parent字段,根据市的parent找到省,根据县的 ...