https://www.luogu.com.cn/problem/P3384
给定一棵大小为 n n n的有点权的无向有根树,要求支持路径增值,子树增值以及它们的查询
数据范围: n ≤ 1 0 5 n\leq 10^5 n≤105
树链剖分练习题,这里简述原理
找出每个节点的重儿子,链的顶端,子树大小
查询/修改 x x x到 y y y的路径,如果已经在同一条链上,直接计算,否则强令 d e p [ t o p [ x ] ] > d e p [ t o p [ y ] ] dep[top[x]]>dep[top[y]] dep[top[x]]>dep[top[y]],然后一直让 x x x跳到 f a [ t o p [ x ] ] fa[top[x]] fa[top[x]],中间计算/修改
子树的话即为 i d [ x ] ∼ i d [ x ] + s i z [ x ] − 1 id[x]\sim id[x]+siz[x]-1 id[x]∼id[x]+siz[x]−1即可
时间复杂度: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
#include
#include
#include
#define N 100010
#define LL long long
using namespace std;int n,m,root,mod,fa[N],l[N],tot,x,y,dep[N],siz[N],son[N],id[N],cnt,top[N],nval[N],opt;
struct node{int next,to;}e[N<<1];
inline void add(int u,int v){e[++tot]=(node){l[u],v};l[u]=tot;return;}
LL val[N],v;
inline LL read()
{
char c;LL d=1,f=0;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void dfs1(int x)
{
siz[x]=1;
int maxn=0;
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]) continue;
dep[y]=dep[x]+1;fa[y]=x;
dfs1(y);
siz[x]+=siz[y];
if(siz[y]>maxn) maxn=siz[son[x]=y];
}
return;
}
inline void dfs2(int x,int topf)
{
id[x]=++cnt;
top[x]=topf;
nval[cnt]=val[x];
if(son[x]==0) return;
dfs2(son[x],topf);
for(register int i=l[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
return;
}
struct xds
{
#define lson k<<1
#define rson k<<1|1
LL sum[N<<2],lzy[N<<2];
inline void pushdown(int k,int l,int r)
{
if(lzy[k]==0) return;
int mid=l+r>>1;
lzy[lson]+=lzy[k];lzy[rson]+=lzy[k];
(sum[lson]+=(mid-l+1)*lzy[k]%mod)%=mod;(sum[rson]+=(r-mid)*lzy[k]%mod)%=mod;
lzy[k]=0;
return;
}
inline void pushup(int k)
{
sum[k]=(sum[lson]+sum[rson])%mod;
return;
}
inline void build(int k=1,int l=1,int r=cnt)
{
if(l==r)
{
sum[k]=nval[l]%mod;
return;
}
int mid=l+r>>1;
build(lson,l,mid);build(rson,mid+1,r);
pushup(k);
return;
}
inline void Modify(int ql,int qr,LL v,int k=1,int l=1,int r=cnt)
{
if(ql<=l&&r<=qr) {lzy[k]+=v;sum[k]+=(r-l+1)*v%mod;return;}
int mid=l+r>>1;
pushdown(k,l,r);
if(ql<=mid) Modify(ql,qr,v,lson,l,mid);
if(qr>mid) Modify(ql,qr,v,rson,mid+1,r);
pushup(k);
return;
}
inline LL Ask(int ql,int qr,int k=1,int l=1,int r=cnt)
{
if(ql<=l&&r<=qr) return sum[k];
LL res=0;int mid=l+r>>1;
pushdown(k,l,r);
if(ql<=mid) res+=Ask(ql,qr,lson,l,mid);
if(qr>mid) res+=Ask(ql,qr,rson,mid+1,r);
pushup(k);
return res;
}
#undef lson
#undef rson
}T;
inline LL qlj(int x,int y)
{
LL res=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
(res+=T.Ask(id[top[x]],id[x]))%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
(res+=T.Ask(id[x],id[y]))%=mod;
return res;
}
inline LL qzs(int x){return T.Ask(id[x],id[x]+siz[x]-1);}
inline void mlj(int x,int y,LL v)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
T.Modify(id[top[x]],id[x],v);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
T.Modify(id[x],id[y],v);
return;
}
inline void mzs(int x,LL v){T.Modify(id[x],id[x]+siz[x]-1,v);}
signed main()
{
n=read();m=read();root=read();mod=read();
for(register int i=1;i<=n;i++) val[i]=read();
for(register int i=1;i<n;i++)
{
x=read();y=read();
add(x,y);add(y,x);
}
dep[root]=1;
dfs1(root);
dfs2(root,root);
T.build();
while(m--)
{
opt=read();
if(opt==1)
{
x=read();y=read();v=read();
mlj(x,y,v);
}
if(opt==2)
{
x=read();y=read();
printf("%lld\n",qlj(x,y)%mod);
}
if(opt==3)
{
x=read();v=read();
mzs(x,v);
}
if(opt==4)
{
x=read();
printf("%lld\n",qzs(x)%mod);
}
}
}