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(树链剖分+线段树)的更多相关文章

  1. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  2. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  3. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  4. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  5. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  6. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  7. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  8. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  9. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

  10. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

随机推荐

  1. asp.net 奇淫技巧

    VS2013自动注释插件 分享一个Visual Studio的背景插件,让堆码更富情趣 工欲善其事必先利其器系列之:更换Visual Studio代码风格. 为Visual Studio更换皮肤和背景 ...

  2. 最小生成树练习2(Kruskal)

    两个BUG鸣翠柳,一行代码上西天... hdu4786 Fibonacci Tree(生成树)问能否用白边和黑边构成一棵生成树,并且白边数量是斐波那契数. 题解:分别优先加入白边和黑边,求出生成树能包 ...

  3. extjs 控件属性

    1.textfield labelSeparator :''   这个属性当fieldLabel有值得时候,默认会加上一个分号,这个属性就是控制那个的... 2.numberfield decimal ...

  4. Octopus系列之开发中灵光点收集,先放到这里,后面会整理的

    项目中引用的组件 1.System.Data.SQLite.dll 自行编译 SQLite-1.0.66.0-source 3.5的框架:F:\Code\开源项目\SQLite\1.0.66.0_x8 ...

  5. 使用Zen coding高效编写html代码

    zen-Coding是一款快速编写HTML,CSS(或其他格式化语言)代码的编辑器插件,这个插件可以用缩写方式完成大量重复的编码工作,是web前端从业者的利器. zen-Coding插件支持多种编辑器 ...

  6. groupadd命令详解(实例)

     groupadd命令详解(实例)  1.作用groupadd命令用于将新组加入系统. 2.格式groupadd [-g gid] [-o]] [-r] [-f] groupname 3.主要参数-g ...

  7. 提升WordPress站点速度的八个建议

    WordPress是一个很棒的开源程序,几乎我认识的站长朋友当中,粗略估算有80%使用Wordpress.但很棒不等于完美,就在我所认识的这些朋友中,几乎所有人都会抱怨Wordpress太臃肿,运行效 ...

  8. 学习KMP算法的一点小心得

    KMP算法应用于 在一篇有n个字母的文档中 查找某个想要查找的长度为m的单词:暴力枚举:从文档的前m个字母和单词对比,然后是第2到m+1个,然后是第3到m+2个:这样算法复杂度最坏就达到了O(m*n) ...

  9. SQL Server 索引介绍

    数据库索引是对数据表中一个或多个列的值进行排序的结构,就像一本书的目录一样,索引提供了在行中快速查询特定行的能力 详细出处参考:http://www.jb51.net/article/30950.ht ...

  10. Program B 暴力求解

    Given a sequence of integers S = {S1,S2,...,Sn}, you should determine what is the value of the maxim ...