树链剖分有这样一个性质,即在剖完之后每个结点下面子树的编号一定是连续的,那么基于这一点,我们记录每个结点的区间就能解决子树更新问题
dfs序也可以解决子树问题,但是这里需要计算一个贡献值,结点的层数不好处理。
#include
#include
#include
#include
using namespace std;
#define maxn 200004
int fir[maxn],nex[maxn],v[maxn],e_max;
int in[maxn],out[maxn],son[maxn],fa[maxn],siz[maxn],deep[maxn],top[maxn],tot;
long long val[maxn],val1[maxn],sum[2*maxn],tag[2*maxn];
void init_()
{
memset(fir,-1,sizeof fir);
memset(son,-1,sizeof son);
e_max=0;
tot=1;
}
void add_edge(int s,int t)
{
int e=e_max++;
v[e]=t;
nex[e]=fir[s];
fir[s]=e;
}
void dfs1(int k,int pre,int d)
{
deep[k]=d;
fa[k]=pre;
siz[k]=1;
for(int i=fir[k];~i;i=nex[i])
{
int e=v[i];
if(e!=pre)
{
dfs1(e,k,d+1);
siz[k]+=siz[e];
if(son[k]==-1||siz[son[k]]>1;
init(l,mid,k<<1);
init(mid+1,r,k<<1|1);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void pushdown(int k,int l,int r)
{
if(!tag[k]) return ;
int mid=l+r>>1;
tag[k<<1]+=tag[k];
tag[k<<1|1]+=tag[k];
sum[k<<1]+=(mid-l+1)*tag[k];
sum[k<<1|1]+=(r-mid)*tag[k];
tag[k]=0;
}
void update(int val,int s,int t,int l,int r,int k)
{
if(s==l&&r==t)
{
tag[k]+=val;
sum[k]+=(long long)(r-l+1)*val;
return ;
}
pushdown(k,l,r);
int mid=l+r>>1;
if(t<=mid) update(val,s,t,l,mid,k<<1);
else if(s>mid) update(val,s,t,mid+1,r,k<<1|1);
else update(val,s,mid,l,mid,k<<1),update(val,mid+1,t,mid+1,r,k<<1|1);
sum[k]=sum[k<<1]+sum[k<<1|1];
}
long long query(int s,int t,int l,int r,int k)
{
if(s==l&&r==t)
{
return sum[k];
}
pushdown(k,l,r);
int mid=l+r>>1;
if(t<=mid) return query(s,t,l,mid,k<<1);
else if(s>mid) return query(s,t,mid+1,r,k<<1|1);
else return query(s,mid,l,mid,k<<1)+query(mid+1,t,mid+1,r,k<<1|1);
}
long long Query(int s,int t)
{
long long sum=0;
int f1=top[s],f2=top[t];
while(f1!=f2)
{
if(deep[f1]deep[t]) swap(s,t);
sum+=query(in[s],in[t],1,tot-1,1);
return sum;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
init_();
for(int i=1;i<=n;i++) scanf("%lld",&val[i]);
for(int i=1;i