还是太弱啊。。各种数据结构只听过名字却没有一点概念。。树链剖分也在这个范畴。。今天来进一步深化一下教育改革推进全民素质提高。

性质

忘了在哪里看到的一篇blog有一句话讲得非常好,树链剖分不是一种数据结构,它只是将二维的树hash到一条一维的链上,为运用各种其他数据结构创造条件。

构造方法(或者说标准 并不知道为什么,然而它就是这么剖的,按照每个节点的儿子个数,相对应地接在其父节点后或自己自成一条重链——这样貌似在平均情况下可以使分成的链条数最少,每条链上的点多——不然为什么不按照顺序...更简单..

维护方法
在一条链上不套个什么东西都太浪费了,那么当我们要更新一条路径时,因为在同一条重链上的点的重编号是连续的,我们可以很方便的更新,再联想我们平时暴力更新的做法——lca,那么我们就可以用这种思想将两个点不断调整上移直到两个点在一条重链内,那么更新的操作就完成了。

BZOJ1036:一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

终于还是A掉了,发现了两个问题..

一个是读入修改的时候忘记把读入的点的编号改成在链中的编号了,这真的是非常。。还有一个就是在LCA往上走的时候在最后自作聪明的想去掉重复——然而结果就是最后那个点根本就不会算!

不管怎么说又多了一个版子——虽然这么长(然而貌似还可以了,毕竟手打并无参考...时间虽然不是非常优秀(比黄学长快啦啦啦

/**************************************************************
Problem: 1036
User: wyc184
Language: C++
Result: Accepted
Time:2400 ms
Memory:7300 kb
****************************************************************/ #define me AcrossTheSky
#include <cstdio>
#include <cmath>
#include <ctime>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> #include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#define lowbit(x) (x)&(-x)
#define INF 1070000000
#define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++)
#define FORP(i,a,b) for(int i=(a);i<=(b);i++)
#define FORM(i,a,b) for(int i=(a);i>=(b);i--)
#define ls(a,b) (((a)+(b)) << 1)
#define rs(a,b) (((a)+(b)) >> 1)
#define MAXN 60001
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
/*==================split line==================*/
struct Edge{
int x,y;
}e[MAXN*2]; int q,xx,L,R;
int n,sume;
int fa[MAXN],size[MAXN],depth[MAXN],sonh[MAXN],ord[MAXN],top[MAXN];
int first[MAXN],next[MAXN];
int max(int a,int b){
return a>b?a:b;
}
struct Interval_Tree{ //线段树最大值和和的维护
int _max[MAXN*2],_sum[MAXN*2],v[MAXN*2]; void updata(int node,int l,int r){
if (l==r) {
v[node]=xx; _max[node]=xx; _sum[node]=xx;
return;
}
int mid=rs(l,r); int lc=ls(node,0),rc=lc+1;
if (q<=mid) updata(lc,l,mid);
else updata(rc,mid+1,r); _max[node]=max(_max[lc],_max[rc]);
_sum[node]=_sum[lc]+_sum[rc];
}
int Max(int node,int l,int r){
if (L<=l && r<=R) return _max[node]; int mid=rs(l,r),lc=ls(node,0),rc=lc+1,m=-INF;
if (L<=mid) m=max(m,Max(lc,l,mid));
if (mid<R) m=max(m,Max(rc,mid+1,r));
return m;
}
int Sum(int node,int l,int r){
if (L<=l && r<=R) return _sum[node]; int mid=rs(l,r),lc=ls(node,0),rc=lc+1,tot=0;
if (L<=mid) tot+=Sum(lc,l,mid);
if (R>mid) tot+=Sum(rc,mid+1,r);
return tot;
}
void check(){
FORP(i,1,n*2) printf("%d ",_max[i]);
cout << endl;
}
}tree;
void addedge(int x,int y){ //邻接表的添加
e[sume].x=x,e[sume].y=y;
next[sume]=first[x];
first[x]=sume;
}
int build_tree(int node,int dep){//树上结点的深度、儿子总数、父亲以及重儿子的维护
depth[node]=dep;
int Max=0,u=0;
for (int i=first[node];i!=-1;i=next[i]){
if (e[i].y!=fa[node]){
fa[e[i].y]=node; int counter=build_tree(e[i].y,dep+1);
if (counter>Max) { Max=counter; u=e[i].y; }
size[node]+=counter;
}
}
sonh[node]=u;
return size[node]+1;
}
int p=1;
void mark(int node,int topn){//重新编号
ord[node]=p;top[node]=topn; if (sonh[node]!=0) {
p++; mark(sonh[node],topn);
}
for (int i=first[node];i!=-1;i=next[i])
if (e[i].y!=fa[node] && e[i].y!=sonh[node]){
p++;
mark(e[i].y,e[i].y);
}
return ;
}
int QSUM(int a,int b){ //求两个点之间的路径和 ——这些操作都是在重编号下完成的
int sum=0;
while (top[a]!=top[b]){ //如果两个点不在一条重链上
if (depth[top[a]]<depth[top[b]]){ //比较两条重链的深度,将深的那条往上调
L=ord[b],R=ord[top[b]]; if (L>R) swap(L,R);
sum+=tree.Sum(1,1,n); //线段树查询
b=fa[top[b]]; //将b更新为这条重链头的父亲
}
else {
L=ord[a],R=ord[top[a]]; if (L>R) swap(L,R);
sum+=tree.Sum(1,1,n);
a=fa[top[a]];
}
}
L=ord[a]; R=ord[b]; if(L>R) swap(L,R);
sum+=tree.Sum(1,1,n);
return sum;
} int QMAX(int a,int b){
int maxx=-INF;
while (top[a]!=top[b]){
if (depth[top[a]]<depth[top[b]]){
L=ord[b],R=ord[top[b]]; if (L>R) swap(L,R);
maxx=max(maxx,tree.Max(1,1,n));
b=fa[top[b]];
}
else {
L=ord[a],R=ord[top[a]]; if (L>R) swap(L,R);
maxx=max(maxx,tree.Max(1,1,n));
a=fa[top[a]];
}
}
L=ord[a]; R=ord[b]; if(L>R) swap(L,R);
maxx=max(maxx,tree.Max(1,1,n));
return maxx;
}
int main(){
cin >> n;
for (int i=1;i<=n;i++) first[i]=-1,size[i]=0; FORP(i,1,n-1){
int x,y; scanf("%d%d",&x,&y);
sume++; addedge(x,y);
sume++; addedge(y,x);
} FORP(i,1,n) fa[i]=i; size[1]=build_tree(1,1)-1; mark(1,1); FORP(i,1,n){
q=ord[i]; scanf("%d",&xx);
tree.updata(1,1,n);
}
int k; cin >> k;
FORP(i,1,k){
char s[10]; scanf("%s",s);
if (s[0]=='C') {
scanf("%d%d",&q,&xx);
q=ord[q];
tree.updata(1,1,n);
continue;
}
int x,y; scanf("%d%d",&x,&y);
if (s[2]=='A') printf("%d\n",QMAX(x,y));
else printf("%d\n",QSUM(x,y));
}
}

BZOJ 1036 && 树链剖分的更多相关文章

  1. BZOJ 4326 树链剖分+二分+差分+记忆化

    去年NOIP的时候我还不会树链剖分! 还是被UOJ 的数据卡了一组. 差分的思想还是很神啊! #include <iostream> #include <cstring> #i ...

  2. bzoj 3083 树链剖分

    首先我们先将树提出一个根变成有根树,那么我们可以通过树链剖分来实现对于子树的最小值求解,那么按照当前的根和询问的点的相对位置关系我们可以将询问变成某个子树和或者除去某颗子树之后其余的和,前者直接询问区 ...

  3. bzoj 2243 树链剖分

    2013-11-19 16:21 原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=2243 树链剖分,用线段树记录该区间的颜色段数,左右端点颜 ...

  4. bzoj 4196 树链剖分 模板

    [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2135  Solved: 1232[Submit][Status][D ...

  5. BZOJ 4811 树链剖分+线段树

    思路: 感觉这题也可神了.. (还是我太弱) 首先发现每一位不会互相影响,可以把每一位分开考虑,然后用树链剖分或者LCT维护这个树 修改直接修改,询问的时候算出来每一位填0,1经过这条链的变换之后得到 ...

  6. HYSBZ 1036树链剖分

    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从 ...

  7. BZOJ 4034 树链剖分

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4034 题意:中文题面 思路:树链剖分入门题. 剖分后就是一个简单的区间更新和区间求和问题. ...

  8. BZOJ 2286 树链剖分+DFS序+虚树+树形DP

    第一次学习虚树,就是把无关的点去掉.S里维护一条链即可. #include <iostream> #include <cstring> #include <cstdio& ...

  9. BZOJ 3083 树链剖分+倍增+线段树

    思路: 先随便选个点 链剖+线段树 1操作 就直接改root变量的值 2操作 线段树上改 3操作 分成三种情况 1.new root = xx 整个子树的min就是ans 2. lca(new roo ...

随机推荐

  1. Kruskal vs Borůvka

    做了个对比.Borůvka算法对于稠密图效果特别好.这两个都是求生成森林的算法.Prim+heap+tarjan过于难写不写了. V=200,E=1000 Kruskal method 4875048 ...

  2. MySQL建立索引的注意事项

    对于大数据量的表格,尤其是百万行以上的数据表,一定要对其建立索引,否则查询速度极慢.(参考后面的测试结果)建立索引时需注意: MySQL的索引有两种:单列索引(即在某一列上建索引).多列组合索引(即在 ...

  3. Couchbase 介绍 - 更好的 Cache 系统

    在移动互联网时代,我们面对的是更多的客户端,更低的请求延迟,这当然需要对数据做大量的 Cache 以提高读写速度. 术语 节点:指集群里的一台服务器. 现有 Cache 系统的特点 目前业界使用得最多 ...

  4. webservice 协议

    Web   Service使用的是   SOAP   (Simple   Object   Access   Protocol)协议soap协议只是用来封装消息用的.封装后的消息你可以通过各种已有的协 ...

  5. Two Sum I & II

    Two Sum I Given an array of integers, find two numbers such that they add up to a specific target nu ...

  6. Java for LeetCode 063 Unique Paths II

    Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How m ...

  7. python 将pdf分页后插入至word中

    所用技术 1. python编程基础 2. 使用pyPdf 3. 使用python操作word 4. 正则表达式的使用 5. windows的bat编程 下面是一个pyPdf库使用的示例: from ...

  8. 【python】

    1.修改系统默认编码: reload(sys) sys.setdefaultencoding('utf-8') 为什么在sys.setdefaultencoding之前要写reload(sys) 因为 ...

  9. July 29th, Week 31st Friday, 2016

    I am a slow walker, but I never walk backwards. 我走得很慢,但我从来不会后退. I had run very fast, and I had once ...

  10. 转:JavaScript事件冒泡简介及应用

    (本文转载自别处) JavaScript事件冒泡简介及应用   一.什么是事件冒泡 在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理 ...