洛谷 P3384 【模板】树链剖分
2016-11-02 20:51
309 查看
题目描述
如题,已知一棵包含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为根节点的子树内所有节点值之和
【题目分析】
模板题目。
【代码】
如题,已知一棵包含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 <cstdio> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,m,root,p,opt,x,y,z; int h[200001],to[200001],ne[200001],en=0; void add(int a,int b) {to[en]=b;ne[en]=h[a];h[a]=en++;} int a[100001]; struct node{ int l,r,sum,tag; }t[4*100001]; int son[100001],fa[100001],dep[100001],siz[100001]; int top[100001],pos[100001],data[100001]; int in[100001],out[100001],cnt=0; void dfs(int k) { siz[k]=1; for (int i=h[k];i>=0;i=ne[i]) if (fa[k]!=to[i]){ fa[to[i]]=k; dep[to[i]]=dep[k]+1; dfs(to[i]); siz[k]+=siz[to[i]]; if (siz[son[k]]<siz[to[i]]) son[k]=to[i]; } } void dfs(int k,int tp) { top[k]=tp; pos[k]=++cnt; in[k]=cnt; data[cnt]=a[k]; if (son[k]) dfs(son[k],tp); for (int i=h[k];i>=0;i=ne[i]) if (fa[k]!=to[i]&&to[i]!=son[k]) dfs(to[i],to[i]); out[k]=cnt; } void build(int k,int l,int r) { t[k].l=l; t[k].r=r; t[k].tag=0; if (l==r) { t[k].sum=data[l]; return ; } build(k*2,l,(l+r)/2); build(k*2+1,(l+r)/2+1,r); t[k].sum=t[k*2].sum+t[k*2+1].sum; return ; } void pud(int k) { if (t[k].l==t[k].r) { t[k].tag=0; return ; } t[k*2].tag+=t[k].tag;t[k*2+1].tag+=t[k].tag; (t[k*2].sum+=t[k].tag*(t[k*2].r-t[k*2].l+1))%=p; (t[k*2+1].sum+=t[k].tag*(t[k*2+1].r-t[k*2+1].l+1))%=p; t[k].tag=0; } void add(int k,int l,int r,int f) { // printf("point %d need add %d to %d is %d\n",k,l,r,f); while (t[k].tag) pud(k); if (t[k].l>r||t[k].r<l) return ; if (t[k].l>=l&&t[k].r<=r) { t[k].tag=f; (t[k].sum+=f*(t[k].r-t[k].l+1))%=p; return ; } add(k*2,l,r,f); add(k*2+1,l,r,f); (t[k].sum=t[k*2].sum+t[k*2+1].sum)%=p; } int qry(int k,int l,int r) { // printf("poinit %d need sum %d to %d\n",k,l,r); while (t[k].tag) pud(k); if (t[k].l>r||t[k].r<l) return 0; if (t[k].l>=l&&t[k].r<=r) return t[k].sum; else return (qry(k*2,l,r)+qry(k*2+1,l,r))%p; } void add1() { scanf("%d%d%d",&x,&y,&z); z%=p; while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); add(1,pos[top[x]],pos[x],z); x=fa[top[x]]; } if (dep[x]<dep[y]) swap(x,y); add(1,pos[y],pos[x],z); } void add2() { scanf("%d%d",&x,&z); z%=p; add(1,in[x],out[x],z); } void qry1() { scanf("%d%d",&x,&y); int ans=0; while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); (ans+=qry(1,pos[top[x]],pos[x]))%=p; // printf("%d is jump now is %d %d\n",fa[top[x]],x,ans); x=fa[top[x]]; } if (dep[x]<dep[y]) swap(x,y); (ans+=qry(1,pos[y],pos[x]))%=p; // printf(" now is %d\n",ans); printf("%d\n",ans); } void qry2() { scanf("%d",&x); int ans=0; (ans=qry(1,in[x],out[x]))%=p; printf("%d\n",ans); } int main() { memset(h,-1,sizeof h); scanf("%d%d%d%d",&n,&m,&root,&p); for (int i=1;i<=n;++i) scanf("%d",&a[i]),a[i]%=p; for (int i=1;i<n;++i) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs(root); dfs(root,root); // for (int i=1;i<=n;++i) printf("%d ",pos[i]); printf("\n"); build(1,1,n); while (m--) { scanf("%d",&opt); if (opt==1) add1(); else if (opt==3) add2(); else if (opt==2) qry1(); else qry2(); } }
相关文章推荐
- 洛谷 P3384 【模板】树链剖分(指针版)
- 【洛谷P3384】【模板】树链剖分
- 洛谷P3384 【模板】树链剖分
- 树链剖分 模板 洛谷P3384
- 树剖模板(洛谷P3384 【模板】树链剖分)(树链剖分,树状数组,树的dfn序)
- 洛谷P3384 【模板】树链剖分
- 洛谷P3384【模板】树链剖分
- 洛谷 P3384 【模板】树链剖分
- 洛谷P3384【模板】树链剖分 (树链剖分)
- AC日记——【模板】树链剖分 洛谷 P3384
- 洛谷 P3384 【模板】树链剖分
- 洛谷树剖模板题 P3384 | 树链剖分
- 洛谷P3384 【模板】树链剖分
- 洛谷——P3384 【模板】树链剖分
- 洛谷 P3384 【模板】树链剖分
- P3384 【模板】树链剖分
- P3384 【模板】树链剖分
- 【洛谷】3384 【模板】树链剖分
- P3384 【模板】树链剖分
- 洛谷3384:【模板】树链剖分——题解