树链剖分
树链剖分就是把一个树分成了几条链。
轻重链剖分:对于一个结点,我们把它所有的儿子结点中子树结点数最大的那个成为重儿子,这样每个结点朝重儿子连边,称为重边,其他边称为轻边,最后重边就构成了若干链。
对于重链,我们用线段树维护信息,查询一条链把它从lca分为两条链,自底向上查询,轻边直接搞,重边在线段树里搞,每次经过轻边节点数加倍,复杂度为\(O(log^2n)\)
操作:
- DFS第一遍,确定子树节点数和重儿子下标
- DFS第二遍,确定DFS序,当前重链顶点,LCA所需信息
- 建出线段树
- 预处理LCA
代码:
struct Edge{
int v,val,next;
} E[maxn*2];
int type,n,m,x,y,size,Esize,val,lca,pos;
int last[maxn],F[maxn][maxlogn],sum[maxn],hs[maxn],A[maxn],vs[maxn],top[maxn],ind[maxn];
int depth[maxn],hv[maxn],T[maxn*3],v[maxn],ex[maxn],ey[maxn];
void addedge(int x,int y,int val)
{
E[++Esize]=(Edge){y,val,last[x]},last[x]=Esize;
E[++Esize]=(Edge){x,val,last[y]},last[y]=Esize;
}
//---------------------------------------
void pre_trans(int k,int fa)
{
sum[k]=1,hs[k]=0; //子树结点和,重儿子
for (int i=last[k];i;i=E[i].next)
if (E[i].v!=fa)
{
pre_trans(E[i].v,k),sum[k]+=sum[E[i].v];
if (sum[E[i].v]>sum[hs[k]]) hs[k]=E[i].v,hv[k]=E[i].val;
}
}
void trans(int k,int fa,int t,int d,int val)
{
if (k!=t) vs[++size]=k,ind[k]=size; //在线段树的下标
F[k][0]=fa,top[k]=t,depth[k]=d,A[k]=val; //父亲,重链顶点
if (hs[k]) trans(hs[k],k,t,d+1,hv[k]);
for (int i=last[k];i;i=E[i].next)
if ((E[i].v!=fa)&&(E[i].v!=hs[k])) trans(E[i].v,k,E[i].v,d+1,E[i].val);
}
//---------------------------------------
int Build_Tree(int k,int l,int r)
{
if (l==r)
T[k]=A[vs[l]];
else
{
int mid=(l+r)>>1;
T[k]=Build_Tree((k<<1),l,mid)+Build_Tree((k<<1)|1,mid+1,r);
}
return T[k];
}
void add(int k,int l,int r,int x,int val)
{
if (l==r)
T[k]=val;
else
{
int mid=(l+r)>>1;
if (x<=mid) add((k<<1),l,mid,x,val); else add((k<<1)|1,mid+1,r,x,val);
T[k]=T[k<<1]+T[(k<<1)|1];
}
}
int min_query(int k,int l,int r,int x,int y)
{
if ((x<=l)&&(r<=y))
return T[k];
else
{
int mid=(l+r)>>1,ans=0;
if (x<=mid) ans+=min_query((k<<1),l,mid,x,y);
if (y>mid) ans+=min_query((k<<1)|1,mid+1,r,x,y);
return ans;
}
}
//---------------------------------------
void LCA_init()
{
rep(k,1,maxlogn-1)
rep(i,1,n) F[i][k]=(F[i][k-1]==-1)?(-1):(F[F[i][k-1]][k-1]);
}
int LCA_query(int x,int y)
{
if (depth[x]>depth[y]) swap(x,y);
rep(k,0,maxlogn-1) if (((depth[y]-depth[x])>>k)&1) y=F[y][k];
if (x==y) return x;
dep(k,maxlogn-1,0) if (F[x][k]!=F[y][k]) x=F[x][k],y=F[y][k];
return F[x][0];
}
//---------------------------------------
void heavylight()
{
pre_trans(1,-1);
trans(1,-1,1,1,0);
Build_Tree(1,1,size);
LCA_init();
}
void update(int x,int y,int val)
{
if (F[x][0]==y) swap(x,y);
if (!ind[y]) A[y]=val; else add(1,1,size,ind[y],val);
}
int ans_query(int k,int t) //查询sum
{
int ans=0,tf,mark=0;
while (!mark)
if (!ind[k])
ans+=A[k],k=F[k][0]; //轻边直接加
else
{
if (top[t]==top[k]) {tf=hs[t];mark=1;} else tf=hs[top[k]];
ans+=min_query(1,1,size,ind[tf],ind[k]); //重边用线段树
k=top[k];
}
return ans;
}

浙公网安备 33010602011771号