性质
忘了在哪里看到的一篇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));
}
}