树链剖分模版

  1 #include <stdio.h>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <string>
  5 #include <algorithm>
  6 #include <queue>
  7 #include <vector>
  8 #include <math.h>
  9 #include <map>
 10 
 11 #define LL long long
 12 using namespace std;
 13 const int maxn = 2e5 + 10;
 14 
 15 struct Edge{
 16     int to,next;
 17 }edge[maxn];
 18 
 19 int tot,head[maxn];
 20 
 21 void add_edge(int u,int v){
 22     edge[++tot] = Edge{v,head[u]};
 23     head[u] = tot;
 24 }
 25 
 26 int mod;
 27 int v[maxn]; // 结点权值
 28 int fa[maxn]; // 父亲
 29 int dep[maxn]; // 深度
 30 int siz[maxn]; // 大小
 31 int son[maxn]; // 重儿子
 32 
 33 // 第一遍的dfs可以得到深度,父亲,大小,重儿子
 34 void dfs1(int u,int f){ // u是当前结点,f是u的父亲
 35     fa[u] = f;
 36     dep[u] = dep[f] + 1;
 37     siz[u] = 1;
 38     int maxsize = -1;  // 判断是不是重儿子的一个临时变量
 39     for (int i=head[u];~i;i=edge[i].next){
 40         int v = edge[i].to;
 41         if (v == f)   //如果是父亲肯定不可以
 42             continue;
 43         dfs1(v,u);
 44         siz[u] += siz[v];
 45         if (siz[v] > maxsize){
 46             maxsize = siz[v];
 47             son[u] = v;  // u的重儿子就是v
 48         }
 49     }
 50 }
 51 
 52 int tim; // 时间戳计数器
 53 int dfn[maxn]; // 时间戳
 54 int top[maxn]; //重链的顶部
 55 int w[maxn]; // 结点权值dfs序
 56 
 57 void dfs2(int u,int t){ // u是当前结点,t是当前结点的重链的头
 58     dfn[u] = ++tim;
 59     top[u] = t;
 60     w[tim] = v[u];
 61     if (!son[u])  // 如果不存在重儿子,那么它就是叶子结点,退出
 62         return;
 63     dfs2(son[u],t);
 64     for (int i=head[u];~i;i=edge[i].next){
 65         int v = edge[i].to;
 66         if (v == fa[u] || v == son[u])   // 往上遍历肯定不可以了,因为前面的dfs2已经遍历了重儿子所以这里也没必要了
 67             continue;
 68         dfs2(v,v);   // 此时这个肯定是轻儿子
 69     }
 70 }
 71 
 72 struct segment_tree{
 73     int l,r,val;
 74     int lazy;
 75 }tree[maxn*4];
 76 
 77 void pushup(int nod){
 78     tree[nod].val = (tree[nod<<1].val + tree[(nod<<1)+1].val) % mod;
 79 }
 80 
 81 void pushdown(int nod){
 82     tree[nod<<1].lazy += tree[nod].lazy;
 83     tree[(nod<<1)+1].lazy += tree[nod].lazy;
 84     tree[nod<<1].val += (tree[nod<<1].r-tree[nod<<1].l + 1) * tree[nod].lazy % mod;
 85     tree[(nod<<1)+1].val += (tree[(nod<<1)+1].r-tree[(nod<<1)+1].l+1) * tree[nod].lazy % mod;
 86     tree[nod].lazy = 0;
 87 }
 88 
 89 void build(int l,int r,int nod=1){
 90     tree[nod].l = l;
 91     tree[nod].r = r;
 92     if (l == r){
 93         tree[nod].lazy = 0;
 94         tree[nod].val = w[l] % mod;
 95         return ;
 96     }
 97     int mid = (l+r)>>1;
 98     build(l,mid,nod<<1);
 99     build(mid+1,r,(nod<<1)+1);
100     pushup(nod);
101 }
102 
103 void modify(int x,int y,int z,int k=1){
104     int l = tree[k].l, r = tree[k].r;
105     if (x<= l && y>=r){
106         tree[k].lazy += z;
107         tree[k].val += (r-l+1) * z;
108         tree[k].val %= mod;
109         return ;
110     }
111     if (tree[k].lazy)
112         pushdown(k);
113     int mid = (l+r)>>1;
114     if (x<=mid){
115         modify(x,y,z,k<<1);
116     }
117     if (y>mid){
118         modify(x,y,z,(k<<1)+1);
119     }
120     pushup(k);
121 }
122 
123 int query(int x,int y,int k=1){
124     int l = tree[k].l,r = tree[k].r;
125     if (x<=l && y>=r){
126         return tree[k].val;
127     }
128     if (tree[k].lazy){
129         pushdown(k);
130     }
131     int sum = 0,mid = (l+r)>>1;
132     if (x <= mid){
133         sum += query(x,y,k<<1);
134     }
135     if (y > mid){
136         sum += query(x,y,(k<<1)+1);
137     }
138     return sum % mod;
139 }
140 
141 void mchain(int x,int y,int z){  // 结点x->结点y 最短路径上所有结点加z
142     z %= mod;
143     while (top[x] != top[y]){
144         if (dep[top[x]] < dep[top[y]])
145             swap(x,y);
146         modify(dfn[top[x]],dfn[x],z);
147         x = fa[top[x]];
148     }
149     if (dep[x] > dep[y])
150         swap(x,y);
151     modify(dfn[x],dfn[y],z);
152 }
153 
154 int qchain(int x,int y){  // 查询x到y结点最短路径上所有节点的值之和
155     int ret = 0;
156     while (top[x] != top[y]){
157         if (dep[top[x]] < dep[top[y]])
158             swap(x,y);
159         ret += query(dfn[top[x]],dfn[x]);
160         x = fa[top[x]];
161     }
162     if (dep[x] > dep[y])
163         swap(x,y);
164     ret += query(dfn[x],dfn[y]);
165     return ret % mod;
166 }
167 
168 void mson(int x,int z){ // 以x为根节点的子树内所有节点值都加上z
169     modify(dfn[x],dfn[x]+siz[x]-1,z);  // 必定是连续的
170 }
171 
172 int qson(int x){  // 以x为根节点的子树内所有节点值之和
173     return query(dfn[x],dfn[x]+siz[x]-1);
174 }
175 
176 
177 int main(){
178     memset(head,-1, sizeof(head));
179     int n,m,r;
180     scanf("%d%d%d%d",&n,&m,&r,&mod);
181     for (int i=1;i<=n;i++){
182         scanf("%d",&v[i]);
183     }
184     for (int i=1;i<n;i++){
185         int u,v;
186         scanf("%d%d",&u,&v);
187         add_edge(u,v);
188         add_edge(v,u);
189     }
190     dfs1(r,r);
191     dfs2(r,r);
192     build(1,n);
193     while (m--){
194         int opt,x,y,z;
195         scanf("%d",&opt);
196         switch(opt){
197             case 1:
198                 scanf("%d%d%d",&x,&y,&z);
199                 mchain(x,y,z);
200                 break;
201             case 2:
202                 scanf("%d%d",&x,&y);
203                 printf("%d\n",qchain(x,y));
204                 break;
205             case 3:
206                 scanf("%d%d",&x,&z);
207                 mson(x,z);
208                 break;
209             case 4:
210                 scanf("%d",&x);
211                 printf("%d\n",qson(x));
212                 break;
213         }
214     }
215     return 0;
216 }

 

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务