(模板)树链剖分
大佬博客
题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
- dfs1处理出重儿子,子树大小,父亲,深度
- dfs2新标号,所在链顶端(用老标号)
- 然后以新标号为下标开线段树
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cctype>
#include <queue>
#include <cstring>
#include <cmath>
using namespace std;
inline int read()
{
int x=0,f=1; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return f*x;
}
typedef long long LL;
#define res register int
const int N=1e5+5;
int head[N],ver[N<<1],nxt[N<<1];
int n,m,tot,r;
LL w[N],P;
inline void add(int x,int y) { ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot;}
int fa[N],dep[N],siz[N],son[N];
/*
Ê÷Á´ÆÊ·Ö£º
1. dfs1 ´¦ÀíÉî¶È£¬Öضù×Ó£¬×ÓÊ÷´óС£¬¸¸Ç×
2. dfs2 бàºÅ£¬¸´ÖƵãȨ£¬¼Ç¼ÿÌõÖØÁ´µÄ¶¥¶Ë
3.Ï߶ÎÊ÷´¦ÀíÁ¬ÐøÇø¼äºÍ
*/
void dfs1(int x,int f)
{
fa[x]=f; dep[x]=dep[f]+1;
siz[x]=1;
for(res i=head[x] ; i ; i=nxt[i])
{
int y=ver[i];
if(y==f) continue;
dfs1(y,x);
siz[x]+=siz[y];
if(siz[y]>siz[son[x]]) son[x]=y;
}
}
int num=0,id[N],top[N];
LL val[N];
void dfs2(int x,int topf)
{
id[x]=++num; val[num]=w[x];
top[x]=topf;
if(!son[x]) return ;
dfs2(son[x],topf);//ÓÅÏÈ´¦ÀíÖضù×Ó
for(res i=head[x] ; i ; i=nxt[i])
{
int y=ver[i]; if(y==son[x]||y==fa[x]) continue;
dfs2(y,y);
}
}
//Ï߶ÎÊ÷£º
LL tag[N<<2],sum[N<<2];
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
inline void pushup(int p)
{sum[p]=(sum[p<<1]+sum[p<<1|1]+P)%P;}
inline void build(int p,int l,int r)
{
if(l==r) {
sum[p]=val[l]; return ;
}
int mid=(l+r)>>1;
build(lson); build(rson);
pushup(p);
}
inline void pushdown(int p,int l,int r,int mid)
{
sum[p<<1]=(sum[p<<1]+(mid-l+1)*tag[p]+P)%P;
sum[p<<1|1]=(sum[p<<1|1]+(r-mid)*tag[p]+P)%P;
tag[p<<1]=(tag[p<<1]+tag[p]+P)%P;
tag[p<<1|1]=(tag[p<<1|1]+tag[p]+P)%P;
tag[p]=0;
}
inline LL query(int p,int l,int r,int ql,int qr)
{
if(ql>qr) swap(ql,qr);
if(ql<=l && r<=qr) return sum[p];
int mid=(l+r)>>1;
pushdown(p,l,r,mid);
LL ret=0;
if(ql<=mid) ret=query(lson,ql,qr)%P;
if(qr>mid) ret=(query(rson,ql,qr)+P+ret)%P;
return ret;
}
inline void change(int p,int l,int r,int ql,int qr,LL k)
{
if(qr<ql) swap(ql,qr);
if(ql<=l && r<=qr)
{
sum[p]+=(LL)(r-l+1)*k;
tag[p]+=k;
return;
}
int mid=(l+r)>>1;
pushdown(p,l,r,mid);
if(ql<=mid) change(lson,ql,qr,k);
if(qr>mid) change(rson,ql,qr,k);
pushup(p);
}
//end
inline LL qson(int p) {
return query(1,1,n,id[p],id[p]+siz[p]-1);
}
inline void cson(int p,int k) {
change(1,1,n,id[p],id[p]+siz[p]-1,k);
}
//²éѯʱÏÈÕÒËùÔÚÁ´µÄ¶¥µã×îÉîµÄ£¬È»ºó²»¶ÏÍùÉÏÌø
inline LL qrange(int x,int y)
{
LL ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);//ÈÃx¸üÉî
ret=(query(1,1,n,id[top[x]],id[x])+ret+P)%P;
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
ret=(ret+P+query(1,1,n,id[y],id[x]))%P;
return ret;
}
inline void crange(int x,int y,int k)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
change(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]<dep[y]) swap(x,y);
change(1,1,n,id[y],id[x],k);
}
int main()
{
// freopen("in.txt","r",stdin);
n=read(); m=read(); r=read(); P=read();
for(res i=1 ; i<=n ; ++i) w[i]=read();
for(res i=1 ; i<n ; ++i) {
int x=read(),y=read();
add(x,y); add(y,x);
}
dfs1(r,0);
dfs2(r,r);
build(1,1,n);
int x,y,k,op;
for(res i=1 ; i<=m ; ++i)
{
op=read();
if(op==1)
{
x=read(); y=read(); k=read();
crange(x,y,k);
}
else if(op==2)
{
x=read(); y=read();
printf("%lld
",qrange(x,y));
}
else if(op==3)
{
x=read(); k=read();
cson(x,k);
}
else
{
x=read();
printf("%lld
",qson(x));
}
}
return 0;
}