树链剖分模板

洛谷P3384【模板】树链剖分·第一个树剖祭


题目描述

如题,已知一棵包含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为根节点的子树内所有节点值之和

输入输出格式

输入格式:

第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

输出格式:

输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)


代码:(感觉自己写的有点长```>_<```······)

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int MAX = 100005;
  4 typedef struct Node{
  5     long long val, tag;
  6     int l, r;
  7     Node *rson, *lson;
  8     int len() {return r - l;}
  9     int mid() {return (l + r) >> 1;}
 10     Node(): rson(NULL), lson(NULL), l(0), r(0), val(0), tag(0){}
 11 }node, *pointer;
 12 
 13 int mod;
 14 
 15 class Segment_Tree
 16 {
 17     public:
 18         pointer rt = new Node();
 19         long long a[MAX];
 20     
 21     void PushUp(pointer rt)
 22         {
 23             rt->val = rt->rson->val + rt->lson->val;
 24         }
 25     
 26     void PushDown(pointer rt)
 27         {
 28             if(rt->tag)
 29                 {
 30                     rt->lson->tag += rt->tag;
 31                     rt->rson->tag += rt->tag;
 32                     rt->lson->val += rt->tag * rt->lson->len();
 33                     rt->rson->val += rt->tag * rt->rson->len();
 34                     rt->tag = 0;
 35                 }
 36         }
 37     
 38     void Build(pointer rt,int l, int r)
 39         {
 40             rt->l = l;
 41             rt->r = r;
 42             if(l + 1 == r)
 43                 {
 44                     rt->val = a[l];
 45                     //rt->pos = l;
 46                     rt->rson = NULL;
 47                     rt->lson = NULL;
 48                     return ;
 49                 }
 50             rt->rson = new Node();
 51             rt->lson = new Node();
 52             Build(rt->lson, l, rt->mid());
 53             Build(rt->rson, rt->mid(), r);
 54             PushUp(rt); 
 55         }
 56         
 57     void UpData(pointer rt, int L, int R, int k)
 58         {
 59             if(L <= rt->l && rt->r <= R)
 60                 {
 61                     rt->val += k * rt->len();
 62                     rt->tag += k;
 63                 }
 64             else
 65                 {
 66                     if(rt->tag != 0)    PushDown(rt);
 67                     if(L < rt->mid())    UpData(rt->lson, L, R, k);
 68                     if(R > rt->mid())     UpData(rt->rson, L, R, k);
 69                     PushUp(rt);
 70                 }
 71         }
 72         
 73     long long Query(pointer rt, int L, int R)
 74         {
 75             if(L <= rt->l && rt->r <= R)    return rt->val;
 76             else
 77                 {
 78                     if(rt->tag != 0)    PushDown(rt);
 79                     long long ret = 0;
 80                     if(L < rt->mid())    ret += Query(rt->lson, L, R);
 81                     if(R > rt->mid()) ret += Query(rt->rson, L, R);
 82                     return ret;
 83                 }
 84         }
 85 };
 86 
 87 class Tree_Chain_Division
 88 {
 89 private:
 90     int Head[MAX], Next[MAX << 1], To[MAX << 1], edgenum = 0;
 91     int size[MAX], Hson[MAX], Father[MAX], Deep[MAX], pos[MAX];
 92     int tid[MAX], ti = 0, top[MAX];
 93     Segment_Tree tree;
 94 
 95     void First_Dfs(int u, int fa)
 96         {
 97             size[u] = 1, Father[u] = fa;
 98             for(int i = Head[u]; i != -1; i = Next[i])
 99                 {
100                     int v = To[i];
101                     if(v == fa) continue;
102                     Deep[v] = Deep[u] + 1;
103                     First_Dfs(v, u);
104                     size[u] += size[v];
105                     if(size[v] > size[Hson[u]] || Hson[u] == 0)    Hson[u] = v;
106                 }
107             return;
108         }
109 
110     void Second_Dfs(int u, int anc)
111         {
112             top[u] = anc, tid[u] = ++ti, pos[ti] = u;
113             if(Hson[u] == 0)    return;
114             Second_Dfs(Hson[u], anc);
115             for(int i = Head[u]; i != -1; i = Next[i])
116                 {
117                     int v = To[i];
118                     if(Father[u] == v || Hson[u] == v)  continue;
119                     Second_Dfs(v, v);
120                 }
121             return ;
122         }
123 
124 public:
125     int a[MAX];
126     
127     void init()
128         {
129             memset(Head, -1, sizeof(Head));
130         }
131 
132     void Add_edge(int from, int to)
133         {
134             Next[++ edgenum] = Head[from];
135             To[edgenum] = to;
136             Head[from] = edgenum;
137         }
138 
139     void Chain_Division(int root, int n)
140         {
141             Deep[root] = 1;
142             First_Dfs(root, 0);
143             Second_Dfs(root, root);
144             for(int i = 1; i <= n; ++ i)    tree.a[i] = a[pos[i]];
145             tree.Build(tree.rt, 1, n + 1);
146             return;
147         }
148 
149     int Get_LCA(int x, int y)
150         {
151             int Father_x = top[x], Father_y = top[y];
152             for(;Father_x != Father_y;)
153                 {
154                     if(Deep[Father_x] < Deep[Father_y])
155                         swap(Father_y, Father_x), swap(x, y);
156                     x = Father[Father_x], Father_x = top[x];
157                 }
158             return Deep[x] < Deep[y] ? x : y;
159         }
160 
161     void Chai_Add(int x, int y, int w) //x y z 表示将树从x到y结点最短路径上所有节点的值都加上w
162         {
163             int Father_x = top[x], Father_y = top[y];
164             for(;Father_x != Father_y;)
165                 {
166                     if(Deep[Father_x] < Deep[Father_y])
167                         swap(Father_y, Father_x), swap(x, y);
168                     tree.UpData(tree.rt, tid[Father_x], tid[x] + 1, w);
169                     x = Father[Father_x], Father_x = top[x];
170                 }
171              if(Deep[x] < Deep[y]) swap(x, y);
172              tree.UpData(tree.rt, tid[y], tid[x] + 1, w);
173              return ;
174         }
175 
176     long long Chai_Query(int x, int y)  //x y 表示求树从x到y结点最短路径上所有节点的值之和
177         {
178             long long ans = 0;
179             int Father_x = top[x], Father_y = top[y];
180             for(;Father_x != Father_y;)
181                 {
182                     if(Deep[Father_x] < Deep[Father_y])
183                         swap(Father_y, Father_x), swap(x, y);
184                     ans = (ans + tree.Query(tree.rt, tid[Father_x], tid[x] + 1)) % mod;
185                     x = Father[Father_x], Father_x = top[x];
186                 }
187             if(Deep[x] < Deep[y])  swap(x, y);
188             ans = (ans + tree.Query(tree.rt, tid[y], tid[x] + 1)) % mod;
189             return ans;
190         }
191 
192     void Tree_Add(int x, int w) //x w 表示将以x为根节点的子树内所有节点值都加上w
193         {
194             tree.UpData(tree.rt, tid[x], tid[x] + size[x], w);
195             return;
196         }
197 
198     long long Tree_Query(int x)  //x 表示求以x为根节点的子树内所有节点值之和
199         {
200             return tree.Query(tree.rt, tid[x], tid[x] + size[x]) % mod; 
201         }
202 };
203 
204 inline int Qread()
205     {
206         int x = 0, w = 0; char ch = getchar();
207         for(;!isdigit(ch);w |= (ch == '-'), ch = getchar());
208         for(;isdigit(ch); x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar());
209         return w ? -x : x;
210     }
211 
212 Tree_Chain_Division division;
213 int main()
214 {
215 //    freopen("sp.in", "r", stdin);
216 //    freopen("sp.out", "w", stdout);
217     
218     int x, y, opt, z, n = Qread(), m = Qread(), root = Qread(); mod = Qread();
219     for(int i = 1; i <= n; ++ i) division.a[i] = Qread();
220     division.init();
221     for(int i = 1; i <  n; ++ i) 
222         {
223             x = Qread(), y = Qread();
224             division.Add_edge(x, y), division.Add_edge(y, x);
225         }
226     division.Chain_Division(root, n);
227     for(int i = 1; i <= m; ++ i)
228         {
229             opt = Qread();
230             switch(opt)
231             {
232                 case 1: x = Qread(), y = Qread(), z = Qread(); division.Chai_Add(x, y, z); break;
233                 case 2: x = Qread(), y = Qread(); printf("%lld
", division.Chai_Query(x, y)); break;
234                 case 3: x = Qread(), y = Qread(); division.Tree_Add(x, y); break;
235                 case 4: x = Qread(); printf("%lld
", division.Tree_Query(x)); break;
236             }
237         }
238     return 0;
239 }
原文地址:https://www.cnblogs.com/2020pengxiyue/p/9296579.html