[luogu]月下“毛景树”:树 剖 好 题

Posted chiarochinoful

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu]月下“毛景树”:树 剖 好 题相关的知识,希望对你有一定的参考价值。

原题


 

题意:

给一棵树 , 每一条边都有边权 , 支持四种操作

1. 将第k条边权值修改为k

2. 将节点u到v的边权都覆盖为k

3. 将节点u到v的边权都增加k

4. 询问区间边权最大值


 

显然树剖

边权转点权然后就是树剖裸题了

怎样边权转点权


 

对于一个点u , 她的父亲是 v

将 u->v 的边权放到 u 上做点权

然后树剖最后的时候这样操作一波

1     if(a == b)
2         return;
3     if(dep[a] > dep[b])
4         std::swap(a, b);
5     SgCover(1, id[a] + 1, id[b], k);

这样就保证了这两个点的 LCA 的点权不会被统计(LCA的点权指向的是 LCA->fa[LCA]  , 很显然不能统计)


 

另一个问题 , 线段树的lazytag

我维护了两个懒标记

一个是 cov , 是覆盖的懒标记

一个是 add , 是增加的懒标记

至于具体用法还是看代码吧 ... 挺好理解的


 

代码:

  1 #include<cmath>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<iostream>
  6 #include<algorithm>
  7 #define APART puts("----------------------")
  8 #define debug 1
  9 #define FILETEST 1
 10 #define inf 100010
 11 #define ll long long
 12 #define ha 998244353
 13 #define INF 0x7fffffff
 14 #define INF_T 9223372036854775807
 15 #define DEBUG printf("%s %d\n",__FUNCTION__,__LINE__)
 16 
 17 namespace chino
 18 
 19 inline void setting()
 20 #if FILETEST
 21     freopen("_test.in", "r", stdin);
 22     freopen("_test.me.out", "w", stdout);
 23 #endif
 24     return;
 25 
 26 
 27 inline int read()
 28     char c = getchar(), up = c; int num = 0;
 29     for(; c < 0 || c > 9; up = c, c = getchar());
 30     for(; c >= 0 && c <= 9; num = (num << 3) + (num << 1) + (c ^ 0), c = getchar());
 31     return  up == - ? -num : num;
 32 
 33 
 34 int n;
 35 int cntE, cntT;
 36 char s[inf];
 37 int mem[inf];
 38 int top[inf];
 39 int dep[inf];
 40 int son[inf];
 41 int fa[inf];
 42 int size[inf];
 43 int id[inf];
 44 int val[inf];
 45 int head[inf << 1];
 46 struct Edge
 47     int to;
 48     int val;
 49     int next;
 50 e[inf << 1];
 51 struct Tree
 52     int l;
 53     int r;
 54     int max;
 55     int cov;
 56     int add;
 57 t[inf << 2];
 58 std::pair <int, int> p[inf];
 59 #define lson(a) (a) << 1
 60 #define rson(a) (a) << 1 | 1
 61 
 62 inline void AddEdge(int from, int to, int val)
 63     ++cntE;
 64     e[cntE].to = to;
 65     e[cntE].val = val;
 66     e[cntE].next = head[from];
 67     head[from] = cntE;
 68     return; 
 69 
 70 
 71 inline int getVal(int now)
 72     if(mem[now])
 73         return mem[now];
 74     for(int i = head[now]; i; i = e[i].next)
 75         if(fa[now] == e[i].to)
 76             return mem[now] = e[i].val;
 77     
 78     return mem[now] = -INF;
 79 
 80 
 81 void Dfs1(int now, int f, int depth)
 82     fa[now] = f;
 83     dep[now] = depth;
 84     size[now] = 1;
 85     int heavy = -INF;
 86     for(int i = head[now]; i; i = e[i].next)
 87         int to = e[i].to;
 88         if(to == f)
 89             continue;
 90         Dfs1(to, now, depth + 1);
 91         int y = size[to];
 92         size[now] += y;
 93         if(y > heavy)
 94             heavy = y;
 95             son[now] = to;
 96         
 97     
 98     return;
 99 
100 
101 void Dfs2(int now, int point)
102     ++cntT;
103     top[now] = point;
104     id[now] = cntT;
105     val[cntT] = (now == 1 ? -INF : getVal(now));
106     if(son[now] == 0)
107         return;
108     Dfs2(son[now], point);
109     for(int i = head[now]; i; i = e[i].next)
110         int to = e[i].to;
111         if(to == fa[now] || to == son[now])
112             continue;
113         Dfs2(to, to);
114     
115     return;
116 
117 
118 using std::max;
119 
120 inline void updata(int now)
121     t[now].max = max (t[lson(now)].max , t[rson(now)].max);
122     return;
123 
124 
125 inline void pushtag(int now)
126     if(t[now].cov != -INF)
127         t[lson(now)].max = t[now].cov;
128         t[rson(now)].max = t[now].cov;
129         t[lson(now)].cov = t[now].cov;
130         t[rson(now)].cov = t[now].cov;
131         t[lson(now)].add = 0;
132         t[rson(now)].add = 0;
133         t[now].cov = -INF;
134     
135     if(t[now].add != 0)
136         t[lson(now)].max += t[now].add;
137         t[rson(now)].max += t[now].add;
138         t[lson(now)].add += t[now].add;
139         t[rson(now)].add += t[now].add;
140         t[now].add = 0;
141     
142     return;
143 
144 
145 void build(int now, int l, int r)
146     t[now].l = l;
147     t[now].r = r;
148     t[now].cov = -INF;
149     if(l == r)
150         t[now].max = val[l];
151         return;
152     
153     int mid = (l + r) >> 1;
154     build(lson(now), l, mid);
155     build(rson(now), mid + 1, r);
156     updata(now);
157     return;
158 
159 void SgCover(int now, int l, int r, int k)
160     if(t[now].l >= l && t[now].r <= r)
161         t[now].cov = t[now].max = k;
162         t[now].add = 0;
163         return;
164     
165     pushtag(now);
166     int mid = (t[now].l + t[now].r) >> 1;
167     if(l <= mid)
168         SgCover(lson(now), l, r, k);
169     if(r > mid)
170         SgCover(rson(now), l, r, k);
171     updata(now);
172     return;
173 
174 
175 void SgAdd(int now, int l, int r, int k)
176     if(t[now].l >= l && t[now].r <= r)
177         t[now].add += k;
178         t[now].max += k;
179         return;
180     
181     pushtag(now);
182     int mid = (t[now].l + t[now].r) >> 1;
183     if(l <= mid)
184         SgAdd(lson(now), l, r, k);
185     if(r > mid)
186         SgAdd(rson(now), l, r, k);
187     updata(now);
188     return; 
189 
190 
191 void SgChange(int now, int x, int k)
192     if(t[now].l > x || t[now].r < x)
193         return;
194     if(t[now].l == t[now].r)
195         t[now].max = k;
196         t[now].cov = -INF;
197         t[now].add = 0;
198         return;
199     
200     pushtag(now);
201     int mid = (t[now].l + t[now].r) >> 1;
202     if(x <= mid)
203         SgChange(lson(now), x, k);
204     else 
205         SgChange(rson(now), x, k);
206     updata(now);
207     return;
208 
209 
210 int SgQuery(int now, int l, int r)
211     if(t[now].l >= l && t[now].r <= r)
212         return t[now].max;
213     pushtag(now);
214     int mid = (t[now].l + t[now].r) >> 1;
215     int Max = -INF;
216     if(l <= mid)
217         Max = max (Max, SgQuery(lson(now), l, r));
218     if(r > mid)
219         Max = max (Max, SgQuery(rson(now), l, r));
220     return Max;
221 
222 
223 inline void cover(int a, int b, int k)
224     while(top[a] != top[b])
225         if(dep[top[a]] < dep[top[b]])
226             std::swap(a, b);
227         SgCover(1, id[top[a]], id[a], k);
228         a = fa[top[a]];
229     
230     if(a == b)
231         return;
232     if(dep[a] > dep[b])
233         std::swap(a, b);
234     SgCover(1, id[a] + 1, id[b], k);
235     return;
236  
237 
238 inline void add(int a, int b, int k)
239     while(top[a] != top[b])
240         if(dep[top[a]] < dep[top[b]])
241             std::swap(a, b);
242         SgAdd(1, id[top[a]], id[a], k);
243         a = fa[top[a]];
244     
245     if(a == b)
246         return;
247     if(dep[a] > dep[b])
248         std::swap(a, b);
249     SgAdd(1, id[a] + 1, id[b], k);
250     return;
251 
252 
253 inline int query(int a, int b)
254     int ans = -INF;
255     while(top[a] != top[b])
256         if(dep[top[a]] < dep[top[b]])
257             std::swap(a, b);
258         ans = max (ans, SgQuery(1, id[top[a]], id[a]));
259         a = fa[top[a]];
260     
261     if(a == b)
262         return ans;
263     if(dep[a] > dep[b])
264         std::swap(a, b);
265     ans = max (ans, SgQuery(1, id[a] + 1, id[b]));
266     return ans;
267 
268 
269 inline int main()
270     n = read();
271     for(int i = 1; i < n; i++)
272         p[i].first  = read();
273         p[i].second = read();
274         int w = read();
275         AddEdge(p[i].first, p[i].second, w);
276         AddEdge(p[i].second, p[i].first, w);
277     
278     Dfs1(1, 0, 1);
279     Dfs2(1, 1);
280     build(1, 1, n);
281     while(true)
282         scanf("%s", s + 1);
283         if(s[1] == S)
284             break;
285         int a = read();
286         int b = read();
287         if(s[2] == a)
288             int ans = query(a, b);
289             printf("%d\n", ans == -INF ? 0 : ans);
290          else if(s[2] == o)
291             cover(a, b, read());
292         else if(s[2] == h)
293             if(fa[p[a].first] == p[a].second)
294                 SgChange(1, id[p[a].first], b);
295             else 
296                 SgChange(1, id[p[a].second],b);
297          else
298             add(a, b, read());
299     
300     return 0;
301 
302 
303 //namespace chino
304 
305 signed main()return chino::main();

附:这题好难写啊 .. 可能是因为我太菜了 .. 很久以前就写过 ... 然后挂了0pts ... 实在不想调一个 350 行的程序 ... 后来今天重构了一遍 ... 不过还是依靠对拍 debug 了好几个小时 ... 码力不行啊 ... 

以上是关于[luogu]月下“毛景树”:树 剖 好 题的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1984月下“毛景树” 树链剖分+线段树

bzoj1984月下“毛景树” 树链剖分+线段树

BZOJ1984 月下“毛景树”

题解 P4315 月下“毛景树”

P4315 月下“毛景树”

bzoj1984 月下“毛景树”