[BZOJ1984]月下“毛景树”解题报告|树链剖分

Description

  毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个。 ? Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。 ? Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问: ? Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个。 ? Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。 ? Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问: ? Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。

  这道题可讲之处显然都在线段树上了...

  事实证明现在的泪都是当年学线段树时脑子进的水...

  1 program bzoj1984;
  2 const maxn=100010;maxm=200010;
  3 var n,i,j,x,y,z,cnt,t:longint;
  4     ch:char;
  5     ter,next,w:array[-1..maxm]of longint;
  6     link,deep,size,v,son,pos,belong:array[-1..maxn]of longint;
  7     tr:array[-1..5*maxn]of record l,r,mx,add,c:longint;wait:boolean;end;
  8     fa:array[-1..maxn,-1..20]of longint;
  9
 10 function max(a,b:longint):longint;
 11 begin
 12     if a>b then exit(a) else exit(b);
 13 end;
 14
 15 procedure add(x,y,z:longint);
 16 begin
 17     inc(j);ter[j]:=y;next[j]:=link[x];link[x]:=j;w[j]:=z;
 18     inc(j);ter[j]:=x;next[j]:=link[y];link[y]:=j;w[j]:=z;
 19 end;
 20
 21 procedure dfs1(p:longint);
 22 var i,j:longint;
 23 begin
 24     size[p]:=1;
 25     for i:=1 to 17 do
 26     begin
 27         if deep[p]<=1 << i then break;
 28         fa[p][i]:=fa[fa[p][i-1]][i-1];
 29     end;
 30     j:=link[p];
 31     while j<>0 do
 32     begin
 33         if deep[ter[j]]=0 then
 34         begin
 35             deep[ter[j]]:=deep[p]+1;
 36             fa[ter[j]][0]:=p;
 37             v[ter[j]]:=w[j];son[(j+1) >> 1]:=ter[j];
 38             dfs1(ter[j]);
 39             inc(size[p],size[ter[j]]);
 40         end;
 41         j:=next[j];
 42     end;
 43 end;
 44
 45 procedure dfs2(p,chain:longint);
 46 var j,k:longint;
 47 begin
 48     inc(cnt);pos[p]:=cnt;belong[p]:=chain;
 49     k:=0;
 50     j:=link[p];
 51     while j<>0 do
 52     begin
 53         if deep[ter[j]]>deep[p] then
 54             if size[ter[j]]>size[k] then k:=ter[j];
 55         j:=next[j];
 56     end;
 57     if k=0 then exit;
 58     dfs2(k,chain);
 59     j:=link[p];
 60     while j<>0 do
 61     begin
 62         if deep[ter[j]]>deep[p] then
 63             if k<>ter[j] then dfs2(ter[j],ter[j]);
 64         j:=next[j];
 65     end;
 66 end;
 67
 68 procedure build(p,l,r:longint);
 69 var mid:longint;
 70 begin
 71     tr[p].l:=l;tr[p].r:=r;tr[p].mx:=0;tr[p].wait:=false;tr[p].add:=0;
 72     if l=r then exit;
 73     mid:=(l+r) >> 1;
 74     build(p << 1,l,mid);
 75     build(p << 1+1,mid+1,r);
 76 end;
 77
 78 procedure push(p:longint);
 79 begin
 80     if tr[p].l=tr[p].r then exit;
 81     if tr[p].wait then
 82     begin
 83         //与上一题不同,这一题并不存在下面的点在更新之后能比现在更好的情况所以不需要push(p << 1);push(p << 1+1)
 84         //否则会TLE
 85         tr[p << 1].add:=0;tr[p << 1+1].add:=0;
 86         //这两句很关键 因为当儿子节点再往下更新的时候如果add没有清零再往下的点会被赋上不等于tr[p].mx的值
 87         tr[p << 1].mx:=tr[p].mx;tr[p << 1].wait:=true;
 88         tr[p << 1+1].mx:=tr[p].mx;tr[p << 1+1].wait:=true;
 89         tr[p].wait:=false;
 90         tr[p].mx:=max(tr[p << 1].mx,tr[p << 1+1].mx);
 91     end;
 92     if tr[p].add<>0 then
 93     begin
 94         inc(tr[p << 1].mx,tr[p].add);
 95         if not tr[p << 1].wait then inc(tr[p << 1].add,tr[p].add);
 96         //这个特判很关键也很隐蔽 因为如果tr[p << 1].wait=True的话它往下传的时候应该把tr[p << 1].mx+tr[p].add传递下去
 97         //但是如果把tr[p << 1].add也加上了tr[p].add的话相当于重复相加 就出错了
 98         inc(tr[p << 1+1].mx,tr[p].add);
 99         if not tr[p << 1+1].wait then inc(tr[p << 1+1].add,tr[p].add);
100         tr[p].add:=0;
101         tr[p].mx:=max(tr[p << 1].mx,tr[p << 1+1].mx);
102     end;
103 end;
104
105 procedure insert(p,l,r,ave:longint);
106 var mid:longint;
107 begin
108     push(p);
109     if (tr[p].l=l)and(tr[p].r=r) then
110     begin
111         tr[p].mx:=ave;tr[p].wait:=true;
112         exit;
113     end;
114     mid:=(tr[p].l+tr[p].r) >> 1;
115     if r<=mid then insert(p << 1,l,r,ave) else
116         if l>mid then insert(p << 1+1,l,r,ave) else
117         begin
118             insert(p << 1,l,mid,ave);
119             insert(p << 1+1,mid+1,r,ave);
120         end;
121     tr[p].mx:=max(tr[p << 1].mx,tr[p << 1+1].mx);
122 end;
123
124 function lca(x,y:longint):longint;
125 var tem,i:longint;
126 begin
127     if deep[x]<deep[y] then
128     begin
129         tem:=x;x:=y;y:=tem;
130     end;
131     if deep[x]<>deep[y] then
132     begin
133         i:=trunc(ln(deep[x]-deep[y])/ln(2));
134         while deep[x]>deep[y] do
135         begin
136             while (deep[x]-deep[y]>=1 << i) do x:=fa[x][i];
137             dec(i);
138         end;
139     end;
140     if x=y then exit(x);
141     i:=trunc(ln(n)/ln(2));
142     while fa[x][0]<>fa[y,0] do
143     begin
144         while fa[x,i]<>fa[y,i] do
145         begin
146             x:=fa[x,i];y:=fa[y,i];
147         end;
148         dec(i);
149     end;
150     exit(fa[x,0]);
151 end;
152
153 procedure add(p,l,r,ave:longint);
154 var mid:longint;
155 begin
156     push(p);
157     if (tr[p].l=l)and(tr[p].r=r) then
158     begin
159         inc(tr[p].mx,ave);
160         inc(tr[p].add,ave);
161         exit;
162     end;
163     mid:=(tr[p].l+tr[p].r) >> 1;
164     if r<=mid then add(p << 1,l,r,ave) else
165         if l>mid then add(p << 1+1,l,r,ave) else
166         begin
167             add(p << 1,l,mid,ave);
168             add(p << 1+1,mid+1,r,ave);
169         end;
170     tr[p].mx:=max(tr[p << 1].mx,tr[p << 1+1].mx);
171 end;
172
173 function query(p,l,r:longint):longint;
174 var mid:longint;
175 begin
176     push(p);
177     if (tr[p].l=l)and(tr[p].r=r) then exit(tr[p].mx);
178     mid:=(tr[p].l+tr[p].r) >> 1;
179     if r<=mid then exit(query(p << 1,l,r)) else
180         if l>mid then exit(query(p << 1+1,l,r)) else
181         exit(max(query(p << 1,l,mid),query(p << 1+1,mid+1,r)));
182 end;
183
184 procedure solve_change(x,y,z:longint);
185 begin
186     while belong[x]<>belong[y] do
187     begin
188         insert(1,pos[belong[x]],pos[x],z);
189         x:=fa[belong[x]][0];
190     end;
191     if x<>y then insert(1,pos[y]+1,pos[x],z);
192 end;
193
194 procedure solve_add(x,y,z:longint);
195 begin
196     while belong[x]<>belong[y] do
197     begin
198         add(1,pos[belong[x]],pos[x],z);
199         x:=fa[belong[x]][0];
200     end;
201     if x<>y then add(1,pos[y]+1,pos[x],z);
202 end;
203
204 function solve_mx(x,y:longint):longint;
205 var sum:longint;
206 begin
207     sum:=0;
208     while belong[x]<>belong[y] do
209     begin
210         sum:=max(sum,query(1,pos[belong[x]],pos[x]));
211         x:=fa[belong[x]][0];
212     end;
213     if x<>y then sum:=max(sum,query(1,pos[y]+1,pos[x]));
214     exit(sum);
215 end;
216
217 begin
218     readln(n);
219     j:=0;
220     for i:=1 to n-1 do
221     begin
222         readln(x,y,z);
223         add(x,y,z);
224     end;
225     deep[1]:=1;dfs1(1);
226     cnt:=0;dfs2(1,1);
227     build(1,1,n);
228     for i:=1 to n do insert(1,pos[i],pos[i],v[i]);
229     read(ch);
230     while ch<>‘S‘ do
231     begin
232         if ch=‘C‘ then
233         begin
234             read(ch);
235             if ch=‘h‘ then
236             begin
237                 readln(ch,ch,ch,ch,x,y);
238                 insert(1,pos[son[x]],pos[son[x]],y);
239             end else
240             begin
241                 readln(ch,ch,ch,x,y,z);
242                 t:=lca(x,y);
243                 solve_change(x,t,z);solve_change(y,t,z);
244             end;
245         end else
246         if ch=‘A‘ then
247         begin
248             readln(ch,ch,x,y,z);
249             t:=lca(x,y);
250             solve_add(x,t,z);solve_add(y,t,z);
251         end else
252         begin
253             readln(ch,ch,x,y);
254             t:=lca(x,y);
255             writeln(max(solve_mx(x,t),solve_mx(y,t)));
256         end;
257         read(ch);
258     end;
259 end.
260     
时间: 2024-08-27 02:51:12

[BZOJ1984]月下“毛景树”解题报告|树链剖分的相关文章

[BZOJ1984] 月下“毛景树”|树链剖分|线段树

1984: 月下“毛景树” Time Limit: 20 Sec  Memory Limit: 64 MBSubmit: 1088  Solved: 348[Submit][Status][Discuss] Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没

bzoj1984 月下“毛景树”

Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个. ? Cover u v w:将节点u与节点

【树链剖分】【分块】【最近公共祖先】【块状树】bzoj1984 月下“毛景树”

裸题,但是因为权在边上,所以要先把边权放到这条边的子节点上,然后进行链更新/查询的时候不能更新/查询其lca. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 100001 #define BN 320 #define INF 2147483647 int fa[N],dep[N],siz[N],son[N],Num[N],tot,top[N],a[N

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

[BZOJ1984]月下"毛景树" Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~~~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: ?

BZOJ 1984: 月下“毛景树”( 树链剖分 )

水水的树链剖分... 将边上的权值转到深度较大的点上 , 然后要注意这样做之后修改或者查询 u , v 转到同一条重链上时 ( 假设 u 深度小 ) , 不能把 u 的权值算上 , 因为是 u 和它的 fa 的边的权值 , 从 u 到 v 并没有经过这条边 线段树维护 3 个域 set , add , max . ---------------------------------------------------------------------------- #include<cstdio

P4315 月下“毛景树”

P4315 月下"毛景树" 题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬毛毛虫爬到了一颗小小的"毛景树"下面,发现树上长着他最爱吃的毛毛果~ "毛景树"上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵"毛景树"有着神奇的魔力,他能改变树枝上毛毛果的个数: Change k w:将第k条

[luogu4315]月下“毛景树”

[luogu4315]月下"毛景树" luogu 联赛前复习一发树剖.不会告诉你WA了4发 #define ls x<<1,l,mid #define rs x<<1|1,mid+1,r #include<bits/stdc++.h> using namespace std; const int _=1e5+5; int re(){ int x=0,w=1;char ch=getchar(); while(ch<'0'||ch>'9'){

【BZOJ】1984 月下“毛景树”

[算法]树链剖分+线段树 [题解]线段树的区间加值和区间覆盖操作不能同时存在,只能存在一个. 修改:从根节点跑到目标区域路上的标记全部下传,打完标记再上传回根节点(有变动才需要上传). 询问:访问到目标区域路上的标记全部下传. 我写的线段树版本是在打标记的同时便对该点的询问项(最大值)做了对应更改,即可保证访问到该点得到的ms就是该点的答案. 访问某点时如果要询问最大值就直接拿走,如果要还要访问该点的子节点就需要下传. 而修改了某点的值,它的祖先的值就都需要变动,所以一旦修改必须上传至顶. 对于

题解 P4315 【月下“毛景树”】

题目链接:Luogu P4315 线段树 \(+\) 树链剖分 \[\Large\texttt{description}\] 给定一棵\(n\)个节点的树,有\(n - 1\)条边相连,给出\(u_i~v_i~w_i\) 分别表示 \(u_i,v_i\)有一条边,边权是\(w_i\) 有\(3\)种操作以及\(1\)种询问 \(\bullet\) Change k w:将第k条树枝上毛毛果的个数改变为w个 \(\bullet\) Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都