用树链剖分解决LCA问题
周日和黄主力吃饭的时候他问我,你会用树链剖分写LCA吗?我说,树链剖分上的LCA和普通倍增LCA有什么区别吗?然后被黄主力大骂一通。。
今天看到一道树链剖分裸题BZOJ3631,就尝试一下直接在树链剖分的同时LCA的方法
树链剖分LCA基本思路:如果两个点不在一条重链上,就移动high[belong[x]]更小的点到fa[belong[x]]
时间复杂度:O(n log n) 空间复杂度:O(n)
模板
int getlca(int x,int y){
for(;belong[x]!=belong[y];x=father[belong[x]])if(high[belong[x]]<high[belong[y]])swap(x,y);
if(pos[x]>pos[y])return y;else return x;
}
BZOJ3631(树链剖分套树状数组)
#include<cstdio>
#include<iostream>
#define N 333333
using namespace std;
int n,i,x,y,tot,sz,ans,a[N],c[N],first[N],size[N],father[N],high[N],pos[N],belong[N],last[N<<1],next[N<<1];
bool vis[N];
void insert(int x,int y){last[++tot]=y;next[tot]=first[x];first[x]=tot;}
void dfs(int x){
size[x]=1;vis[x]=1;
for(int i=first[x];i;i=next[i])
if(!vis[y=last[i]]){
father[y]=x;high[y]=high[x]+1;
dfs(y);size[x]+=size[y];
}
}
void dfs2(int x,int f){
int now=0;pos[x]=++sz;belong[x]=f;
for(int i=first[x];i;i=next[i])if(size[y=last[i]]>size[now]&&high[x]<high[y])now=y;
if(!now)return;dfs2(now,f);
for(int i=first[x];i;i=next[i])if(high[x]<high[y=last[i]]&&now!=y)dfs2(y,y);
}
int lowbit(int x){return x&(-x);}
void change(int x,int z){for(;x<=n&&x;x+=lowbit(x))c[x]+=z;}
int query(int x){ans=0;for(;x;x-=lowbit(x))ans+=c[x];return ans;}
void queryin(int x,int y){//树链剖分LCA部分
for(;belong[x]!=belong[y];x=father[belong[x]]){
if(high[belong[x]]<high[belong[y]])swap(x,y);
change(pos[belong[x]],1);change(pos[x]+1,-1);
}
if(pos[x]>pos[y])swap(x,y);
change(pos[x],1);change(pos[y]+1,-1);
}
int main(){
scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<n;i++)scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
dfs(1);dfs2(1,1);
for(i=1;i<n;i++)queryin(a[i],a[i+1]);
for(i=2;i<=n;i++)change(pos[a[i]],-1),change(pos[a[i]]+1,1);
for(i=1;i<=n;i++)printf("%d\n",query(pos[i]));
}
这样写的树链剖分真是短,压代码以后1031B,BZOJ上最短
BZOJ1103 树剖傻逼题,直接树剖LCA再合适不过了
#include<cstdio>
#define N 252500
int n,i,x,y,tot,m,sum,ans,id,fir[N],la[N<<1],ne[N<<1],c[N],fa[N],bl[N],pos[N],h[N],sz[N];
void ins(int x,int y){la[++tot]=y;ne[tot]=fir[x];fir[x]=tot;}
void add(int x,int y){for(;x<=n;x+=x&-x)c[x]+=y;}char s[9];
int qu(int x){for(sum=0;x;x-=x&-x)sum+=c[x];return sum;}
void dfs(int x){
int i,y;sz[x]=1;
for(i=fir[x];i;i=ne[i])if(fa[x]!=(y=la[i]))fa[y]=x,h[y]=h[x]+1,dfs(y),sz[x]+=sz[y];
}
void dfs2(int x,int f){
int now=0,i;pos[x]=++id;bl[x]=f;
for(i=fir[x];i;i=ne[i])if(sz[y=la[i]]>sz[now]&&h[x]<h[y])now=y;
if(!now)return;dfs2(now,f);
for(i=fir[x];i;i=ne[i])if(h[x]<h[y=la[i]]&&now!=y)dfs2(y,y);
}
int main(){
for(scanf("%d",&n),i=1;i<n;i++)scanf("%d%d",&x,&y),ins(x,y),ins(y,x);
dfs(1);dfs2(1,1);for(i=2;i<=n;i++)add(i,1);
for(scanf("%d",&m),m+=n-1;m--;){
scanf("%s",s);if(s[0]=='W'){
scanf("%d",&x);
for(ans=0;bl[1]!=bl[x];x=fa[bl[x]])ans+=qu(pos[x])-qu(pos[bl[x]]-1);
printf("%d\n",ans+qu(pos[x])-qu(pos[1]-1));
}else scanf("%d%d",&x,&y),add(pos[y],-1);
}
}
2015年6月09日 14:12
你最短你很自豪么。。
2015年6月19日 12:33
被lbn大D一通