洛谷树剖模板题 P3384 | 树链剖分
Posted MSPqwq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷树剖模板题 P3384 | 树链剖分相关的知识,希望对你有一定的参考价值。
对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树
剩下的就和树剖一样了
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define N 100010 5 typedef long long ll; 6 using namespace std; 7 int ecnt,head[N],son[N],fa[N],sz[N],n,m,r,deep[N],pos[N],indx[N],tot,op,back[N],top[N]; 8 ll val[N],P; 9 struct adj 10 { 11 int nxt,v; 12 }e[2*N]; 13 struct node 14 { 15 int l,r; 16 ll sum,lz; 17 }t[4*N]; 18 void add(int u,int v) 19 { 20 e[++ecnt].v=v; 21 e[ecnt].nxt=head[u]; 22 head[u]=ecnt; 23 e[++ecnt].v=u; 24 e[ecnt].nxt=head[v]; 25 head[v]=ecnt; 26 } 27 void dfs1(int x,int father,int dep) 28 { 29 deep[x]=dep,fa[x]=father,sz[x]=1; 30 for (int i=head[x];i;i=e[i].nxt) 31 { 32 int v=e[i].v; 33 if (fa[x]==v) continue; 34 dfs1(v,x,dep+1); 35 sz[x]+=sz[v]; 36 if (sz[v]>sz[son[x]]) son[x]=v; 37 } 38 } 39 void dfs2(int x,int TOP) 40 { 41 top[x]=TOP; 42 pos[x]=++tot; 43 indx[tot]=x; 44 if (son[x]) dfs2(son[x],TOP); 45 for (int i=head[x];i;i=e[i].nxt) 46 { 47 int v=e[i].v; 48 if (v==fa[x] || v==son[x]) continue; 49 dfs2(v,v); 50 } 51 back[x]=tot; 52 } 53 void pushdown(int p) 54 { 55 if (t[p].l==t[p].r || !t[p].lz) return; 56 int w=t[p].lz; 57 t[p<<1].sum=(t[p<<1].sum+w*(t[p<<1].r-t[p].l+1)%P)%P; 58 t[p<<1|1].sum=(t[p<<1|1].sum+w*(t[p<<1|1].r-t[p<<1|1].l+1)%P)%P; 59 t[p<<1].lz+=w; 60 t[p<<1].lz%=P; 61 t[p<<1|1].lz+=w; 62 t[p<<1|1].lz%=P; 63 t[p].lz=0; 64 } 65 void pushup(int p) 66 { 67 t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%P; 68 } 69 void build(int p,int l,int r) 70 { 71 t[p].l=l,t[p].r=r,t[p].lz=0; 72 if (l!=r) 73 { 74 int mid=l+r>>1; 75 build(p<<1,l,mid); 76 build(p<<1|1,mid+1,r); 77 pushup(p); 78 } 79 else 80 t[p].sum=val[indx[l]]%P; 81 } 82 void modify(int p,int l,int r,int w) 83 { 84 if (t[p].l==l && t[p].r==r) 85 { 87 t[p].sum+=w*(t[p].r-t[p].l+1); 88 t[p].lz+=w; 89 return ; 90 } 91 pushdown(p); 92 int mid=t[p].l+t[p].r>>1; 93 if (r<=mid) modify(p<<1,l,r,w); 94 else if (l>mid) modify(p<<1|1,l,r,w); 95 else modify(p<<1,l,mid,w),modify(p<<1|1,mid+1,r,w); 96 pushup(p); 97 } 98 ll query(int p,int l,int r) 99 { 100 if (t[p].l==l && t[p].r==r) 101 return t[p].sum%P; 102 int mid=t[p].l+t[p].r>>1; 103 pushdown(p); 104 if (r<=mid) return query(p<<1,l,r)%P; 105 if (l>mid) return query(p<<1|1,l,r)%P; 106 return (query(p<<1,l,mid)+query(p<<1|1,mid+1,r))%P; 107 } 108 void pathInc(int u,int v,int w) 109 { 110 while (top[u]!=top[v]) 111 { 112 if (deep[top[u]]<deep[top[v]]) swap(u,v); 113 modify(1,pos[top[u]],pos[u],w); 114 u=fa[top[u]]; 115 } 116 if (deep[u]>deep[v]) swap(u,v); 117 modify(1,pos[u],pos[v],w); 118 } 119 ll pathQuery(int u,int v) 120 { 121 ll ret=0; 122 while (top[u]!=top[v]) 123 { 124 if (deep[top[u]]<deep[top[v]]) swap(u,v); 125 ret=(ret+query(1,pos[top[u]],pos[u]))%P; 126 u=fa[top[u]]; 127 } 128 if (deep[u]>deep[v]) swap(u,v); 129 return (ret+query(1,pos[u],pos[v]))%P; 130 } 131 int main() 132 { 133 scanf("%d%d%d%lld",&n,&m,&r,&P); 134 for (int i=1;i<=n;i++) 135 scanf("%lld",&val[i]); 136 for (int i=1,u,v;i<n;i++) 137 scanf("%d%d",&u,&v),add(u,v); 138 dfs1(r,0,0); 139 dfs2(r,r); 140 build(1,1,n); 141 for (int i=1,x,y,z;i<=m;i++) 142 { 143 scanf("%d",&op); 144 if (op==1) 145 scanf("%d%d%d",&x,&y,&z),pathInc(x,y,z); 146 else if (op==2) 147 scanf("%d%d",&x,&y),printf("%lld\n",pathQuery(x,y)); 148 else if (op==3) 149 scanf("%d%d",&x,&z),modify(1,pos[x],back[x],z); 150 else scanf("%d",&x),printf("%lld\n",query(1,pos[x],back[x])); 151 } 152 return 0; 153 }
以上是关于洛谷树剖模板题 P3384 | 树链剖分的主要内容,如果未能解决你的问题,请参考以下文章