7th 2022/6/10 树链剖分
开头的话
终于理解了!!!
树链剖分,算法如其名,就是:把——树——剖——成——几——条——链
链,是重链,即按子节点子树中节点最多的分
这里的“几”字,可不是随便用的
而是真的,只有\(\log n\)条!!!
emmm,所以在理解这个前,我一直认为树链剖分非常暴力
但……
有艺术的算法
这个算法的大概框架了解一下先
就是剖成多条链,然后标号后,同一条链上的节点编号也是连续的
连续???没错,线段树&树状数组乱入
emmm这两个算法总结以后会写
但,作为RMQ的主力,他们俩完全能够胜任连续编号节点的处理
就这样。。。树剖结束了
总的来说就是分成3部分
-
初始化,树剖需要的各个数据,
如:父亲节点,深度,子书节点个数,重儿子节点,重链的顶部,树剖后的编号,和这个编号所对应的原来编号
-
RMQ的初始化
-
游戏开始,查询吧
注意:若查询的两个节点在一条链上,便直接RMQ他们
但若不在,那么两个结点便不断\(O(1)\)
地跳到当前链的链顶,一边跳一边记录
当然,要取两个点中,点的链顶较深的那个
不然一个领先另一个一堆,后面还没找到LCA,就先跳到root了
直到在同一条链(很好判断的,就是链顶相同,因为链互不相交)
不用怕链很多,因为他们就\(\log n\)个啊
就是这样啦
注意多复习,毕竟人总是会忘记事情的嘛。。。
代码(给出线段树,应用广,此处为查询路径和)
#include<cstdio>
using namespace std;
const int N=3e4+1;
int n,m,root,*a[N],len[N],b[N];
int fa[N],deep[N],size[N],top[N],dfn[N],bh[N],big_son[N];
int bz[N],x[N],y[N],kind,s,t,ans,cnt;
int f[4*N];
void swap(int &a,int &b){
int g=a;a=b;b=g;
}
void cut_into_tree(int x){
bz[x]=1;
for(int i=1;i<=a[x][0];i++){
if(bz[a[x][i]]==1){
a[x][i]=-1;
continue;
}
cut_into_tree(a[x][i]);
}
}
void dfs1(int x,int fath,int now_deep){
fa[x]=fath;
deep[x]=now_deep;
for(int i=1;i<=a[x][0];i++){
if(a[x][i]==-1){
continue;
}
dfs1(a[x][i],x,now_deep+1);
size[x]+=size[a[x][i]];
}
size[x]++;
}
void dfs2(int x,int head){
int mx=-2147483647,mxi;
dfn[x]=++cnt;
top[x]=head;
int sum=0;
for(int i=1;i<=a[x][0];i++){
if(a[x][i]==-1){
continue;
}
sum++;
if(size[a[x][i]]>mx){
mx=size[a[x][i]];
mxi=i;
}
}
if(sum>0){
big_son[x]=mxi;
dfs2(a[x][mxi],head);
for(int i=1;i<=a[x][0];i++){
if(a[x][i]==-1||i==mxi){
continue;
}
dfs2(a[x][i],a[x][i]);
}
}
}
void build(int l,int r,int s){
if(l==r){
f[s]=b[bh[l]];
return;
}
int mid=(l+r)/2;
build(l,mid,s*2);
build(mid+1,r,s*2+1);
f[s]=f[s*2]+f[s*2+1];
}
void change(int l,int r,int s,int x,int y){
if(l<=dfn[x]&&dfn[x]<=r){
if(l==r){
f[s]=y;
return;
}
int mid=(l+r)/2;
change(l,mid,s*2,x,y);
change(mid+1,r,s*2+1,x,y);
f[s]=f[s*2]+f[s*2+1];
}
}
int query(int l,int r,int s,int x,int y){
if(y<l||r<x){
return 0;
}
if(x<=l&&r<=y){
return f[s];
}
if(l==r){
return 0;
}
int mid=(l+r)/2;
return query(l,mid,s*2,x,y)+query(mid+1,r,s*2+1,x,y);
}
int get_link(int s,int t){
ans=0;
while(top[s]!=top[t]){
if(deep[top[s]]>deep[top[t]]){
ans+=query(1,n,1,dfn[top[s]],dfn[s]);
s=fa[top[s]];
}
else{
ans+=query(1,n,1,dfn[top[t]],dfn[t]);
t=fa[top[t]];
}
}
if(deep[s]>deep[t]){
swap(s,t);
}
ans+=query(1,n,1,dfn[s],dfn[t]);
return ans;
}
int main(){
scanf("%d%d",&n,&m);
root=1;
for(int i=1;i<n;i++){
scanf("%d%d",&x[i],&y[i]);
len[x[i]]++;
len[y[i]]++;
}
for(int i=1;i<=n;i++){
a[i]=new int[len[i]+1];
a[i][0]=0;
}
for(int i=1;i<n;i++){
a[x[i]][++a[x[i]][0]]=y[i];
a[y[i]][++a[y[i]][0]]=x[i];
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
cut_into_tree(root);
dfs1(root,-1,1);
dfs2(root,root);
for(int i=1;i<=n;i++){
bh[dfn[i]]=i;
}
build(1,n,1);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&kind,&s,&t);
if(kind==1){
change(1,n,1,s,t);
}
else{
printf("%d\n",get_link(s,t));
}
}
}

浙公网安备 33010602011771号