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. Integer 与int 的区别

    int 是java 提供的8 种原始数据类型之一.Java 为每个原始类型提供了封装类,Integer 是java 为int 提供的封装类.int 的默认值为0,而Integer 的默认值为null, ...

  2. Setting my home here

    New here (For no chinese input on this machine, I have to use English.) Why do I choose here ? Whene ...

  3. 从零开始学 Java - CentOS 下安装 Nginx

    早上下起了暴雨 闹钟还未响起就听到雨滴哗啦啦击打窗户的声音,被吵醒了.起床上班,在楼下的十字路口,暴雨大到完全看不清对面,两个穿着雨衣的交警站在路口中间指挥着过往的车辆,大家都慌慌张张.急急忙忙的打着 ...

  4. 工业串口和网络软件通讯平台(SuperIO 2.1)更新发布

    SuperIO 2.1下载 一.SuperIO 的特点: 1)    能够很快的构建自己的通讯平台软件,包括主程序. 2)   设备模块化开发,通过配制文件挂载,即可在平台软件下运行. 3)   设备 ...

  5. 纯CSS3魔方的制作

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  6. HTML5学习之 开发工具

    Notepad++.Editplus 是常用的开发编辑器.这些在Window系统下,比较容易找到,但是在MAC系统下,有的是收费的,有的是不支持.我开发的时候,用的是TextWrangler,如图: ...

  7. iOS 修改状态栏字体的颜色

    在实际开发中,状态栏有时,需要我们自己设置: 比如: 默认状态栏 假如我们开发的view是黑色的,那么效果如图: 状态栏是白底黑字,下面的view是黑底? 这样子真的好吗?说好的和谐社会呢?说好的开发 ...

  8. 自己写一个 jQuery 插件

    我知道这一天终将会到来,现在,它来了. 需求 开发 SharePoint 的 CSOM 应用时,经常需要在网页上输出一些信息. 这种需求和 alert 的弹窗.F12 的断点查看信息的场景是不一样的: ...

  9. Linux常用命令:sed

    本文记录的是自己在学习<Linux私房菜>中正则表达式的笔记. 关于行尾符$ 如果文件本身没有内容,比如使用touch新建的文件,那么$将会没有意义.例如下面操作: 先使用touch新建了 ...

  10. SQL SERVER作业的Schedules浅析

    SQL SERVER作业的计划(Schedules),如果你没仔细研究过或没有应用一些复杂的计划(Schedules),那么你觉得SQL SERVER作业的计划(Schedules)非常好用,也没啥问 ...