具体见OI-wiki,下面是一些补充
重链要求是极大的
每个点都在某一个重链中,如果一个点是重子节点,那么其在与其父亲所连的边的重链中,否则在与其重子节点所连的边的重链中
这一段的原因:我们走重链是不用关心的,因为同一重链的dfs序是连续的,我们可以用其他数据结构维护,我们只用关心这条路径被划分成了多少条重链以及哪些重链,而重链一旦改变,肯定会经过轻边,也就是说最多划分成\(O(\log n)\)条重链
然后划分链的过程:由于重边属于唯一一条重链,所以我们直接从当前点往上走(沿着重边)走到当前重链的最上面的一个点(这条重链的顶点),然后统计这一段的答案,并循环即可,具体见代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+10;
int n,w[maxn],q;
int cur,Last[maxn],Next[maxn<<1],End[maxn<<1];
int sz[maxn],tp[maxn],son[maxn],dep[maxn],fa[maxn],dfn[maxn],rk[maxn],cnt,maxdfn[maxn];
ll sum[maxn<<2],lazy[maxn<<2];
void add(int x,int y)
{
End[++cur]=y,Next[cur]=Last[x],Last[x]=cur;
}
void dfs1(int x,int father)
{
son[x]=-1;
sz[x]=1;
for(int i=Last[x];i;i=Next[i])
{
int u=End[i];
if(u==father) continue;
dep[u]=dep[x]+1;
fa[u]=x;
dfs1(u,x);
sz[x]+=sz[u];
if(son[x]==-1||sz[son[x]]<sz[u])
son[x]=u;
}
}
void dfs2(int x,int t)
{
tp[x]=t;//tp[x]表示x所在重链的顶点
cnt++;
dfn[x]=cnt;
rk[cnt]=x;
if(son[x]==-1)
{
maxdfn[x]=cnt;
return;
}
dfs2(son[x],t);//注意第二个参数是t
maxdfn[x]=maxdfn[son[x]];
for(int i=Last[x];i;i=Next[i])
{
int u=End[i];
if(u!=fa[x]&&u!=son[x])
{
dfs2(u,u);//注意两个参数都是u
maxdfn[x]=max(maxdfn[x],maxdfn[u]);
}
}
}
void build(int p,int l,int r)
{
if(l==r)
{
sum[p]=w[rk[l]];
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void pushdown(int p,int l,int r)
{
int mid=l+r>>1;
lazy[p<<1]+=lazy[p],sum[p<<1]+=lazy[p]*(mid-l+1);
lazy[p<<1|1]+=lazy[p],sum[p<<1|1]+=lazy[p]*(r-mid);
lazy[p]=0;
}
void modify(int p,int l,int r,int x,int y,ll val)
{
if(l>y||r<x) return;
if(l>=x&&r<=y)
{
lazy[p]+=val;
sum[p]+=(r-l+1)*val;
return;
}
pushdown(p,l,r);
int mid=l+r>>1;
modify(p<<1,l,mid,x,y,val);
modify(p<<1|1,mid+1,r,x,y,val);
sum[p]=sum[p<<1]+sum[p<<1|1];
}
void modify1(int x,int y,ll val)
{
int fx=tp[x],fy=tp[y];
while(fx!=fy)
{
if(dep[fx]>=dep[fy])
modify(1,1,n,dfn[fx],dfn[x],val),x=fa[fx];
else
modify(1,1,n,dfn[fy],dfn[y],val),y=fa[fy];
fx=tp[x];
fy=tp[y];
}
if(dfn[x]<dfn[y])
modify(1,1,n,dfn[x],dfn[y],val);
else
modify(1,1,n,dfn[y],dfn[x],val);
}
ll ask(int p,int l,int r,int x,int y)
{
if(l>y||r<x) return 0;
if(l>=x&&r<=y) return sum[p];
pushdown(p,l,r);
int mid=l+r>>1;
return ask(p<<1,l,mid,x,y)+ask(p<<1|1,mid+1,r,x,y);
}
ll query1(int x,int y)
{
ll res=0;
int fx=tp[x],fy=tp[y];
while(fx!=fy)
{
if(dep[fx]>=dep[fy])
res+=ask(1,1,n,dfn[fx],dfn[x]),x=fa[fx];
else
res+=ask(1,1,n,dfn[fy],dfn[y]),y=fa[fy];
fx=tp[x];
fy=tp[y];
}
if(dfn[x]<dfn[y])
res+=ask(1,1,n,dfn[x],dfn[y]);
else
res+=ask(1,1,n,dfn[y],dfn[x]);
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dfs1(1,0);
dfs2(1,1);//注意第二个参数是1
build(1,1,n);
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
modify1(u,v,k);
}
else if(op==2)
{
int u,k;
scanf("%d%d",&u,&k);
modify(1,1,n,dfn[u],maxdfn[u],k);
}
else if(op==3)
{
int u,v;
scanf("%d%d",&u,&v);
printf("%lld\n",query1(u,v));
}
else
{
int u;
scanf("%d",&u);
printf("%lld\n",ask(1,1,n,dfn[u],maxdfn[u]));
}
}
return 0;
}
标签:剖分,fx,fy,tp,树链,dfn,maxn,重链
From: https://www.cnblogs.com/dingxingdi/p/18364302