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

性质

忘了在哪里看到的一篇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. 友盟消息推送和更新XML配置

    <receiver android:name="com.umeng.message.NotificationProxyBroadcastReceiver" android:e ...

  2. 代码风格与树形DP

    Streaming很惨,不过因为比赛之间没有提交过就没掉(或掉了)rating.第二题是一个树形DP,但是我都在想第一题了,简直作死. 看着神犇的代码我也是醉了...各种宏,真是好好写会死系列. 看到 ...

  3. shell 生成指定范围随机数与随机字符串 .

    shell 生成指定范围随机数与随机字符串         分类:             shell              2014-04-22 22:17     20902人阅读     评 ...

  4. Moebius集群:SQL Server一站式数据平台

    一.Moebius集群的架构及原理 1.无共享磁盘架构 Moebius集群采用无共享磁盘架构设计,各个机器可以不连接一个共享的设备,数据可以存储在每个机器自己的存储介质中.这样每个机器就不需要硬件上的 ...

  5. SharePoint 2010整体进行验证

    http://www.cnblogs.com/Sunmoonfire/archive/2010/02/09/1666861.html SharePoint 2010的一个新特性就是在列表条目创建时会针 ...

  6. 61. 从1到n,共有n个数字,每个数字只出现一次。从中随机拿走一个数字x,请给出最快的方法,找到这个数字。如果随机拿走k(k>=2)个数字呢?[find k missing numbers from 1 to n]

    [本文链接] http://www.cnblogs.com/hellogiser/p/find-k-missing-numbers-from-1-to-n.html  [题目] 从1到n,共有n个数字 ...

  7. iOS 中使用Block时需要注意的retain circle

    现在在ios中,block是越来越多了.自己在类中定义block对象时,需要注意block对象的使用方法,防止产生retain circle,导致内存泄露. 现在分析一下产生retain circle ...

  8. Windows下使用命令行设置ip地址的DNS服务器

    使用命令行或者编写bat批处理设置网络连接的IP地址以及DNS服务器地址有时候会比手动更加方便,IP地址和DNS的设置一般是配合的,常用到的几个状态是: 1.IP地址动态获取,DNS也动态 2.IP地 ...

  9. Java for LeetCode 072 Edit Distance【HARD】

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...

  10. codeforces 488A. Giga Tower 解题报告

    题目链接:http://codeforces.com/problemset/problem/488/A 题目意思:给出一个数a,范围是[-10^9, 10^9],问它最少需要加的一个正整数 b 是多少 ...