1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 14302  Solved: 5779
[Submit][Status][Discuss]

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

学了一下树链剖分,感觉几月前的自己好弱,现在理解起来比较简单

一个链接

摘抄alpq654321课件上一些东西:

  • 树链剖分,指一种对树进行划分的算法,它先通过轻重边剖分将树分为多条链,保证每个点属于且只属于一条链,然后再通过数据结构(树状数组、SBT、SPLAY、线段树等)来维护每一条链。
  • 第一遍dfs求出树每个结点的深度deep[x],其为根的子树大小size[x],以及每个点的父亲fa[x]。
  • 第二遍dfs以根节点为起点,先dfs其儿子中size最大的儿子,相当于重边,之后dfs其它轻儿子。
  • ž在dfs的过程中求出每个节点的dfs序以及沿着重链向根最远到达哪个点,每条重链的dfs序就相当于一段区间,树上问题转化为区间问题。
  • 根据不同题目使用维护区间的数据结构即可。
  • 每次要对一条链进行处理时,比较简单的做法是求出LCA后将其分为两条链。
  • 对于每次操作,将当前点跳到其最远的重链祖先,这些点的dfs序是连续的,当做区间操作来处理。

性质:

  • 对于所有轻边u,v。
  • 有size[v]*2<size[u]。
  • 因此对于任意一点开始到根为止,最多不超过lgn条轻边。
  • 显然重链与轻边的条数同阶,因此也不超过lgn条重链。

一些注意:

1.每个节点属于一条重链

2.因为先走重链,所以他的dfs序构成线段(代码中用了tid

这个也是n

3.我的dfs第一次还处理了mx[u],u的子节点size最大的

4.读入w的时候直接用了tid,建树的时候比较方便,要不然如果使用线段树build函数必须加一个fmp[x]表示tid为x的点的原编号[一定要分清哪个编号]

5.求lca就是交替走重链和轻边,选择deep[top[]]大的点走到fa[top[]](过程中可以对重链操作),最后x和y在同一条重链上了,直接操作

[2016-12-31]一些新理解:

复杂度:每走一个轻边,size至少一倍(可以想想完全二叉树,那个正好一倍),最多走logn次

完全二叉树才是logn,然后这样树高太小卡不住暴力,所以认为树剖的常数很小

链剖序同时是dfs序,但要注意重链先行

一个小性质:除了最后的链,每个区间都是重链的一个前缀

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define lc o<<1
#define rc o<<1|1
#define m ((l+r)>>1)
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
const int N=3e4+,INF=1e9;
int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x*f;
}
int n,a,b,w[N],q;
char s[];
struct edge{
int v,ne;
}e[N<<];
int h[N],cnt;
inline void ins(int u,int v){
cnt++;
e[cnt].v=v;e[cnt].ne=h[u];h[u]=cnt;
cnt++;
e[cnt].v=u;e[cnt].ne=h[v];h[v]=cnt;
}
int deep[N],size[N],fa[N],mx[N];
void dfs1(int u){
size[u]=;
for(int i=h[u];i;i=e[i].ne){
int v=e[i].v;
if(v==fa[u]) continue;
fa[v]=u;deep[v]=deep[u]+;
dfs1(v);
size[u]+=size[v];
if(size[v]>size[mx[u]]) mx[u]=v;
}
}
int tid[N],top[N],tot;
void dfs2(int u,int anc){
if(!u) return;
tid[u]=++tot;top[u]=anc;
dfs2(mx[u],anc);
for(int i=h[u];i;i=e[i].ne)
if(e[i].v!=mx[u]&&e[i].v!=fa[u]) dfs2(e[i].v,e[i].v);
} struct node{
int sum,mx;
}t[N<<];
void merge(int o){
t[o].sum=t[lc].sum+t[rc].sum;
t[o].mx=max(t[lc].mx,t[rc].mx);
}
void build(int o,int l,int r){
if(l==r) t[o].sum=t[o].mx=w[l];
else{
build(lson);
build(rson);
merge(o);
}
}
void change(int o,int l,int r,int p,int v){
if(l==r) t[o].sum=t[o].mx=v;
else{
if(p<=m) change(lson,p,v);
else change(rson,p,v);
merge(o);
}
}
int segsum(int o,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return t[o].sum;
else{
int ans=;
if(ql<=m) ans+=segsum(lson,ql,qr);
if(m<qr) ans+=segsum(rson,ql,qr);
return ans;
}
}
int segmx(int o,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return t[o].mx;
else{
int mx=-INF;
if(ql<=m) mx=max(mx,segmx(lson,ql,qr));
if(m<qr) mx=max(mx,segmx(rson,ql,qr));
return mx;
}
}
int qmax(int x,int y){
int mx=-INF;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y);
mx=max(mx,segmx(,,n,tid[top[x]],tid[x]));
x=fa[top[x]];
}
if(tid[x]>tid[y]) swap(x,y);
mx=max(mx,segmx(,,n,tid[x],tid[y]));
return mx;
}
int qsum(int x,int y){
int sum=;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]]) swap(x,y);
sum+=segsum(,,n,tid[top[x]],tid[x]);
x=fa[top[x]];
}
if(tid[x]>tid[y]) swap(x,y);
sum+=segsum(,,n,tid[x],tid[y]);
return sum;
}
int main(){
n=read();
for(int i=;i<=n-;i++) a=read(),b=read(),ins(a,b);
dfs1();dfs2(,);
for(int i=;i<=n;i++) w[tid[i]]=read(); build(,,n);//tot==n
q=read();
while(q--){
scanf("%s",s);a=read();b=read();
if(s[]=='M') printf("%d\n",qmax(a,b));
else if(s[]=='S') printf("%d\n",qsum(a,b));
else w[a]=b,change(,,n,tid[a],b);
}
}

BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】的更多相关文章

  1. Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT

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

  2. BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )

    树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...

  3. bzoj 1036: [ZJOI2008]树的统计Count 树链剖分+线段树

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

  4. BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

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

  5. BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分)(线段树单点修改)

    [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14968  Solved: 6079[Submit][Stat ...

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

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

  7. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

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

  8. Cogs 1688. [ZJOI2008]树的统计Count(树链剖分+线段树||LCT)

    [ZJOI2008]树的统计Count ★★★ 输入文件:bzoj_1036.in 输出文件:bzoj_1036.out 简单对比 时间限制:5 s 内存限制:162 MB [题目描述] 一棵树上有n ...

  9. BZOJ 1036 [ZJOI2008]树的统计Count (树链剖分 - 点权剖分 - 单点权修改)

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 树链剖分模版题,打的时候注意点就行.做这题的时候,真的傻了,单词拼错检查了一个多小时 ...

随机推荐

  1. Error LNK1104 cannot open file 'libboost_system-vc140-mt-gd-1_58.lib'

    I had a similar problem when trying to use boost unit testing in Visual Studio 2015 (Community Editi ...

  2. java中 try return finally return

    finally块里面的代码一般都是会执行的,除非执行 System.exit(int),停止虚拟机,断电. 1.若try代码块里面有return ,假设要return 的值 是A,A为基本类型或者被f ...

  3. CSS3文本溢出显示省略号

    CCS3属性之text-overflow:ellipsis;的用法和注意之处 语法: text-overflow:clip | ellipsis 默认值:clip 适用于:所有元素 clip: 当对象 ...

  4. jQuery带tab切换搜索框样式代码

    效果体验:http://hovertree.com/texiao/jquery/23/ 代码如下,保存到HTML文件也可以查看效果: <!DOCTYPE html> <html la ...

  5. linux文件目录详解

    文件系统的是用来组织和排列文件存取的,所以她是可见的,在Linux中,我们可以通过ls等工具来查看其结构,在Linux系统中,我们见到 的都是树形结构:比如操作系统安装在一个文件系统中,他表现为由/起 ...

  6. 在Linux上使用Nginx为Solr集群做负载均衡

    在Linux上使用Nginx为Solr集群做负载均衡 在Linux上搭建solr集群时需要用到负载均衡,但测试环境下没有F5 Big-IP负载均衡交换机可以用,于是先后试了weblogic的proxy ...

  7. Storm基础

    Storm基本概念 Storm是一个开源的实时计算系统,它提供了一系列的基本元素用于进行计算:Topology.Stream.Spout.Bolt等等. 在Storm中,一个实时应用的计算任务被打包作 ...

  8. Play Framework 完整实现一个APP(八)

    创建Tag标签 1.创建Model @Entity @Table(name = "blog_tag") public class Tag extends Model impleme ...

  9. 【scikit-learn】scikit-learn的线性回归模型

     内容概要 怎样使用pandas读入数据 怎样使用seaborn进行数据的可视化 scikit-learn的线性回归模型和用法 线性回归模型的评估測度 特征选择的方法 作为有监督学习,分类问题是预 ...

  10. 整型信号量和PV操作(计算机操作系统)

    在整型信号量机制中,信号量被定义为一个整形变量.除初始化外,仅能通过两个标准的原子操作Wait(S)和Signal(S)来访问.其通常分别被称为P.V操作. 描述如下: P操作:S=S-1:如果S小于 ...