树链剖分:
通过两次dfs,分别对每个节点为根节点的树的节点个数,重点,父亲节点,深度与重链头结点,在线段树上对应的id,每个id对应的原本序列rk,进行初始化。
这样就完成了树链剖分。剩下的就是在在剖分过得树上进行求和,更新操作。
洛谷p3384
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
const int M=1e5+100;
int f[M];
int d[M];
int siz[M];
int rk[M];//保存树链剖分后,节点编号对应树上位置
int id[M];//节点剖分后所对应的编号,id[rk[x]]]=x;
int top[M];
int son[M];
int n,m,r,q;
int tr[M*4],lazy[M*4],cnt,a[M];
vector<int>v[M];
void dfs1(int rt,int now,int dep)
{
siz[now]=1;
f[now]=rt;
d[now]=dep;
for(int i=0;i<v[now].size();i++)
{
if(v[now][i]!=rt)
{
dfs1(now,v[now][i],dep+1);
siz[now]+=siz[v[now][i]];
if(siz[v[now][i]]>siz[son[now]])
son[now]=v[now][i];
}
}
}
void dfs2(int now,int t)
{
top[now]=t;
id[now]=++cnt;
rk[cnt]=now;
if(!son[now])
{
return;
}
dfs2(son[now],t);//将重链链接在一起
for(int i=0;i<v[now].size();i++)
{
if(v[now][i]!=son[now]&&v[now][i]!=f[now])
{
dfs2(v[now][i],v[now][i]);
}
}
}
void pushup(int i)
{
tr[i]=tr[i*2]+tr[i*2+1];
tr[i]%=q;
}
void pushdown(int i,int l,int r)
{
int mid=(l+r)/2;
lazy[i<<1]=(lazy[i<<1]+lazy[i])%q;
lazy[i<<1|1]=(lazy[i<<1|1]+lazy[i])%q;
tr[i<<1]=(tr[i<<1]+lazy[i]*(mid-l+1))%q;
tr[i<<1|1]=(tr[i<<1|1]+lazy[i]*(r-mid))%q;
lazy[i]=0;
}
void build(int i,int l,int r)
{
if(l==r)
{
lazy[i]=0;
tr[i]=a[rk[l]]%q;
return ;
}
lazy[i]=0;
int mid=(l+r)/2;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
pushup(i);
}
void update(int i,int l,int r,int x,int y,int t)
{
if(x<=l&&y>=r)
{
tr[i]=(tr[i]+(r-l+1)*t)%q;
lazy[i]=(lazy[i]+t)%q;
return;
}
if(lazy[i]!=0)
pushdown(i,l,r);
int mid=(l+r)/2;
if(x<=mid)
{
update(i*2,l,mid,x,y,t);
}
if(y>mid)
{
update(i*2+1,mid+1,r,x,y,t);
}
pushup(i);
}
int query(int i,int l,int r,int x,int y)
{
if(x<=l&&y>=r)
{
return tr[i];
}
if(lazy[i]!=0)
pushdown(i,l,r);
int ans=0;
int mid=(l+r)/2;
if(x<=mid)
ans+=query(i*2,l,mid,x,y);
if(y>mid)
ans+=query(i*2+1,mid+1,r,x,y);
ans%=q;
return ans;
}
int ask(int x,int y)
{
int ans=0;
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
ans=(ans+query(1,1,n,id[fx],id[x]))%q;
x=f[top[x]];
fx=top[x];
}
if(d[x]>d[y])
swap(x,y);
ans=(ans+query(1,1,n,id[x],id[y]))%q;
return ans;
}
void qupdate(int x,int y,int t)
{
t%=q;
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
update(1,1,n,id[fx],id[x],t);
x=f[top[x]];
fx=top[x];
}
if(d[x]>d[y])
swap(x,y);
update(1,1,n,id[x],id[y],t);
}
int main()
{
cnt=0;
scanf("%d%d%d%d",&n,&m,&r,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(0,r,1);
dfs2(r,r);
build(1,1,n);
while(m--)
{
int op;
int x,y,z;
scanf("%d",&op);
switch (op)
{
case 1:
scanf("%d%d%d",&x,&y,&z);
qupdate(x,y,z);
break;
case 2:
scanf("%d%d",&x,&y);
printf("%d\n",ask(x,y));
break;
case 3:
scanf("%d%d",&x,&z);
update(1,1,n,id[x],id[x]+siz[x]-1,z);
break;
case 4:
scanf("%d",&x);
printf("%d\n",query(1,1,n,id[x],id[x]+siz[x]-1)%q);
break;
}
}
return 0;
}
洛谷p3178
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
const int M=1e5+100;
long long f[M];
long long d[M];
long long siz[M];
long long rk[M];//保存树链剖分后,节点编号对应树上位置
long long id[M];//节点剖分后所对应的编号,id[rk[x]]]=x;
long long top[M];
long long son[M];
long long n,m;
long long tr[M*4],lazy[M*4],cnt,a[M];
vector<long long>v[M];
void dfs1(long long rt,long long now,long long dep)
{
siz[now]=1;
f[now]=rt;
d[now]=dep;
for(long long i=0;i<v[now].size();i++)
{
if(v[now][i]!=rt)
{
dfs1(now,v[now][i],dep+1);
siz[now]+=siz[v[now][i]];
if(siz[v[now][i]]>siz[son[now]])
son[now]=v[now][i];
}
}
}
void dfs2(long long now,long long t)
{
top[now]=t;
id[now]=++cnt;
rk[cnt]=now;
if(!son[now])
{
return;
}
dfs2(son[now],t);//将重链链接在一起
for(long long i=0;i<v[now].size();i++)
{
if(v[now][i]!=son[now]&&v[now][i]!=f[now])
{
dfs2(v[now][i],v[now][i]);
}
}
}
void pushup(long long i)
{
tr[i]=tr[i*2]+tr[i*2+1];
}
void pushdown(long long i,long long l,long long r)
{
long long mid=(l+r)/2;
lazy[i<<1]=(lazy[i<<1]+lazy[i]);
lazy[i<<1|1]=(lazy[i<<1|1]+lazy[i]);
tr[i<<1]=(tr[i<<1]+lazy[i]*(mid-l+1));
tr[i<<1|1]=(tr[i<<1|1]+lazy[i]*(r-mid));
lazy[i]=0;
}
void build(long long i,long long l,long long r)
{
if(l==r)
{
lazy[i]=0;
tr[i]=a[rk[l]];
return ;
}
lazy[i]=0;
long long mid=(l+r)/2;
build(i*2,l,mid);
build(i*2+1,mid+1,r);
pushup(i);
}
void update(long long i,long long l,long long r,long long x,long long y,long long t)
{
if(x<=l&&y>=r)
{
tr[i]=(tr[i]+(r-l+1)*t);
lazy[i]=(lazy[i]+t);
return;
}
if(lazy[i]!=0)
pushdown(i,l,r);
long long mid=(l+r)/2;
if(x<=mid)
{
update(i*2,l,mid,x,y,t);
}
if(y>mid)
{
update(i*2+1,mid+1,r,x,y,t);
}
pushup(i);
}
long long query(long long i,long long l,long long r,long long x,long long y)
{
if(x<=l&&y>=r)
{
return tr[i];
}
if(lazy[i]!=0)
pushdown(i,l,r);
long long ans=0;
long long mid=(l+r)/2;
if(x<=mid)
ans+=query(i*2,l,mid,x,y);
if(y>mid)
ans+=query(i*2+1,mid+1,r,x,y);
return ans;
}
long long ask(long long x,long long y)
{
long long ans=0;
long long fx=top[x],fy=top[y];
while(fx!=fy)
{
if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
ans=(ans+query(1,1,n,id[fx],id[x]));
x=f[top[x]];
fx=top[x];
}
if(d[x]>d[y])
swap(x,y);
ans=(ans+query(1,1,n,id[x],id[y]));
return ans;
}
void qupdate(long long x,long long y,long long t)
{
long long fx=top[x],fy=top[y];
while(fx!=fy)
{
if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
update(1,1,n,id[fx],id[x],t);
x=f[top[x]];
fx=top[x];
}
if(d[x]>d[y])
swap(x,y);
update(1,1,n,id[x],id[y],t);
}
int main()
{
cnt=0;
scanf("%lld%lld",&n,&m);
for(long long i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(long long i=0;i<n-1;i++)
{
long long x,y;
scanf("%lld%lld",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs1(0,1,1);
dfs2(1,1);
build(1,1,n);
while(m--)
{
long long op;
int x,y;
scanf("%lld",&op);
switch (op)
{
case 1:
scanf("%d%d",&x,&y);
update(1,1,n,id[x],id[x],y);
break;
case 2:
scanf("%d%d",&x,&y);
update(1,1,n,id[x],id[x]+siz[x]-1,y);
break;
case 3:
scanf("%d",&x);
printf("%lld\n",ask(1,x));
break;
}
}
return 0;
}