【洛谷3384】树链剖分模板
题面
如题,已知一棵包含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为根节点的子树内所有节点值之和
代码
写挂的几个地方:跳链是跳到链端的父亲,比较深度也是比较链端的深度。
- #include<bits/stdc++.h>
- using namespace std;
- #define N 100010
- #define lc (p<<1)
- #define rc (p<<1|1)
- #define ll long long
- #define mid (t[p].l+t[p].r>>1)
- ll n,m,op,cnt,tot,mod,root;
- ll a[N],d[N],f[N],id[N],rk[N],son[N],siz[N],top[N],first[N];
- struct email
- {
- ll u,v;
- ll nxt;
- }e[N*4];
- void add(ll u,ll v)
- {
- e[++cnt].nxt=first[u];first[u]=cnt;
- e[cnt].v=v;e[cnt].u=u;
- }
- struct tree
- {
- ll l,r,sum,lazy;
- }t[N*4];
- inline void pushnow(ll p,ll v)
- {
- t[p].sum=(t[p].sum+(t[p].r-t[p].l+1)*v%mod)%mod;
- t[p].lazy=(v+t[p].lazy)%mod;
- }
- inline void pushdown(ll p)
- {
- if(t[p].lazy)
- {
- pushnow(lc,t[p].lazy);
- pushnow(rc,t[p].lazy);
- t[p].lazy=0;
- }
- }
- inline void pushup(ll p)
- {
- t[p].sum=(t[lc].sum+t[rc].sum)%mod;
- }
- inline void build(ll p,ll l,ll r)
- {
- t[p].l=l;t[p].r=r;
- if(l==r)
- {
- t[p].sum=a[rk[l]];
- return ;
- }
- ll bmid=l+r>>1;
- build(lc,l,bmid);build(rc,bmid+1,r);
- pushup(p);
- }
- inline void update(ll p,ll ql,ll qr,ll v)
- {
- if(ql<=t[p].l&&qr>=t[p].r)
- {
- pushnow(p,v);
- return ;
- }
- pushdown(p);
- if(ql<=mid)update(lc,ql,qr,v);
- if(qr>mid)update(rc,ql,qr,v);
- pushup(p);
- }
- inline ll query(ll p,ll ql,ll qr)
- {
- ll ret=0;
- if(ql<=t[p].l&&qr>=t[p].r)
- return t[p].sum;
- pushdown(p);
- if(ql<=mid) ret=(ret+query(lc,ql,qr))%mod;
- if(qr>mid) ret=(ret+query(rc,ql,qr))%mod;
- return ret;
- }
- inline void dfs1(ll u,ll fa,ll dep)
- {
- d[u]=dep;f[u]=fa;siz[u]=1;
- for(ll i=first[u];i;i=e[i].nxt)
- {
- ll v=e[i].v;
- if(v==fa)continue;
- dfs1(v,u,dep+1);
- siz[u]+=siz[v];
- if(siz[v]>siz[son[u]])
- son[u]=v;
- }
- }
- inline void dfs2(ll u,ll t)
- {
- top[u]=t;id[u]=++tot;
- rk[tot]=u;
- if(son[u]==0)return;
- dfs2(son[u],t);
- for(ll i=first[u];i;i=e[i].nxt)
- {
- ll v=e[i].v;
- if(v!=f[u]&&v!=son[u])
- dfs2(v,v);
- }
- }
- void updtree(ll x,ll y,ll v)
- {
- ll fx=top[x],fy=top[y];
- while(fx!=fy)
- {
- if(d[fx]>=d[fy])
- {
- update(1,id[fx],id[x],v);
- x=f[fx];fx=top[x];
- }
- else
- {
- update(1,id[fy],id[y],v);
- y=f[fy];fy=top[y];
- }
- }
- if(id[x]<=id[y])update(1,id[x],id[y],v);
- else update(1,id[y],id[x],v);
- }
- ll asktree(ll x,ll y)
- {
- ll ret=0;
- ll fx=top[x],fy=top[y];
- while(fx!=fy)
- {
- if(d[fx]>=d[fy])
- {
- ret=(ret+query(1,id[fx],id[x]))%mod;
- x=f[fx];fx=top[x];
- }
- else
- {
- ret=(ret+query(1,id[fy],id[y]))%mod;
- y=f[fy];fy=top[y];
- }
- }
- if(id[x]<=id[y])ret=(ret+query(1,id[x],id[y]))%mod;
- else ret=(ret+query(1,id[y],id[x]))%mod;
- return ret%mod;
- }
- int main()
- {
- scanf("%lld%lld%lld%lld",&n,&m,&root,&mod);
- for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);
- for(ll i=1;i<n;i++)
- {
- ll u,v;
- scanf("%lld%lld",&u,&v);
- add(u,v);add(v,u);
- }
- dfs1(root,0,1);
- dfs2(root,root);
- build(1,1,n);
- for(ll i=1;i<=m;i++)
- {
- ll x,y,z;
- scanf("%lld",&op);
- if(op==1)
- {
- scanf("%lld%lld%lld",&x,&y,&z);
- updtree(x,y,z);
- }
- if(op==2)
- {
- scanf("%lld%lld",&x,&y);
- printf("%lld\n",asktree(x,y));
- }
- if(op==3)
- {
- scanf("%lld%lld",&x,&z);
- update(1,id[x],id[x]+siz[x]-1,z);
- }
- if(op==4)
- {
- scanf("%lld",&x);
- printf("%lld\n",query(1,id[x],id[x]+siz[x]-1));
- }
- }
- return 0;
- }
“Make my parents proud,and impress the girl I like.”