树链剖分模板
Posted hhhen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分模板相关的知识,希望对你有一定的参考价值。
题目链接:https://www.luogu.com.cn/problem/P3178
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:
- 操作 1 :把某个节点 x 的点权增加 a 。
- 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
- 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入格式
第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出格式
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
输入 #1
5 5 1 2 3 4 5 1 2 1 4 2 3 2 5 3 3 1 2 1 3 5 2 1 2 3 3
输出 #1
6 9 13
说明/提示
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+9; const double ep=1e-6; const int mod=998244353; const int MAX=1e9; #define mk make_pair #define PII pair<int,int> #define PLL pair<ll,ll> #define pb push_back typedef long long ll; ll n,m,b[maxn],size[maxn],d[maxn]; ll f[maxn][20]; vector<int>vec[maxn]; ll be[maxn]; ll pp[maxn],cnt; struct node{ ll l,r,sum,lazy; }a[maxn<<2]; void dfs(int x,int p) { size[x]=1; for(int j:vec[x]) { if(j==p)continue; f[j][0]=x; d[j]=d[x]+1; dfs(j,x); size[x]+=size[j]; } } void dfs1(int x,int chain,int p) { be[x]=chain; pp[x]=++cnt; int pos=0; for(int j:vec[x]) { if(j==p)continue; if(size[j]>size[pos])pos=j; } if(!pos)return; dfs1(pos,chain,x); for(int j:vec[x]) { if(j==p||j==pos)continue; dfs1(j,j,x); } } int lca(int a,int b) { if(d[a]<d[b])swap(a,b); for(int i=17;i>=0;i--)if((d[a]-d[b])>>i)a=f[a][i]; if(a==b)return a; for(int i=17;i>=0;i--)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i]; return f[a][0]; } void build(int k,int l,int r) { a[k].l=l,a[k].r=r; if(l==r)return; int mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void pushup(int k) { a[k].sum=a[k<<1].sum+a[k<<1|1].sum; } void pushdown(int k) { if(a[k].l==a[k].r) { a[k].lazy=0;return; } a[k<<1].sum+=(a[k<<1].r-a[k<<1].l+1)*a[k].lazy; a[k<<1|1].sum+=(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lazy; a[k<<1].lazy+=a[k].lazy; a[k<<1|1].lazy+=a[k].lazy; a[k].lazy=0; } void change(int k,int l,int r,int x) { if(a[k].l>=l&&a[k].r<=r) { a[k].sum+=(a[k].r-a[k].l+1)*x; a[k].lazy+=x; return; } if(a[k].lazy)pushdown(k); int mid=(a[k].l+a[k].r)>>1; if(l<=mid)change(k<<1,l,r,x); if(r>mid)change(k<<1|1,l,r,x); pushup(k); } ll query_SUM(int k,int l,int r) { if(a[k].lazy)pushdown(k); if(a[k].l>=l&&a[k].r<=r) { return a[k].sum; } int mid=(a[k].l+a[k].r)>>1; if(r<=mid)return query_SUM(k<<1,l,r); else if(l>mid)return query_SUM(k<<1|1,l,r); else return query_SUM(k<<1,l,mid)+query_SUM(k<<1|1,mid+1,r); } ll query(int x) { ll sum1=0; while(be[x]!=1) { sum1+=query_SUM(1,pp[be[x]],pp[x]); x=f[be[x]][0]; } sum1+=query_SUM(1,1,pp[x]); return sum1; } int main() { scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++)scanf("%lld",&b[i]); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); vec[u].pb(v); vec[v].pb(u); } dfs(1,0); for(int i=1;i<=17;i++)for(int j=1;j<=n;j++)f[j][i]=f[f[j][i-1]][i-1]; dfs1(1,1,-1); build(1,1,n); for(int i=1;i<=n;i++)change(1,pp[i],pp[i],b[i]); while(m--) { int op,x,y; scanf("%d%d",&op,&x); if(op==1) { scanf("%d",&y); change(1,pp[x],pp[x],y); } if(op==2) { scanf("%d",&y); change(1,pp[x],pp[x]+size[x]-1,y); } if(op==3) { printf("%lld ",query(x)); } } }
以上是关于树链剖分模板的主要内容,如果未能解决你的问题,请参考以下文章