题目大意
一个
n
个节点的树,点带有权值
定义
会有
Q
次操作,形如:
每次操作之后,你都需要找到一个点
x
,最小化
请输出 w 。
数据保证任何时候
d
都为非负数。
题目分析
这题显然就是求树的带权重心。
首先我们想一下最暴力的方法。一个点貌似可以过官配数据)。
这个方法没有利用好树的重心(这里以及下文的“重心”指的都是不带权重心)的性质。显然我们要找的带权重心要么为某个点,要么在某个点的一颗固定的子树里。这是可以使用点分治优化的。
令
fx
表示分治中心
x
的整个分治块所有点的
先讲讲怎么查询,假设当前处理分治中心
x
,我们需要做的事情是:
- 枚举
x 在分治树里面的所有儿子 y ,查看是否存在2fy>total 。- 如果不存在,那么我们要找的点就是 x ,退出即可。否则进入第3步。
- 设不满足条件的儿子为
z ,我们递归到 z 那里找即可。但是在找之前我们需要修改一下f ,令 x 到分治块z 的连边指向点 u ,那么点u 在分治树中到 z 路径上所有点的f 都要加上 fx−fz 。找到答案退出时记得将加上的数改回来。 然后我们找到了带权重心 c ,怎么统计答案呢?我们可以从
c 开始一直向分治树中的父亲节点跳,令 l 为上一个点,然后每个点x 会对答案造成的贡献有 gx 以及 dist(x,c)×(fx−fl) ,当然还要减去 hl 。具体为什么希望读者自行推导。修改时我们只需要从修改点开始向分治树中的父亲节点跳,将沿途的点 f 、
g 和h h 都加上相应的值即可,这个也由读者习性脑补。时间复杂度
O(nlog2n+Qlog2n) 。
代码实现
这道题很久以前做的,只是为了做课件挖出来写写题解。
久远到什么程度呢?那个时候我还是用 Pascal 的。const Maxn=100005; Maxe=(Maxn-1)<<1; Maxel=Maxn<<1-1; MaxLgel=trunc(ln(Maxel)/ln(2)); var Que,App,Last,First,Size,Invfa,Corefa,Orig,Up,High:array[1..Maxn]of longint; Tov,Next,Len,Aim,Prev:array[1..Maxe]of longint; Rmq:array[1..Maxel,0..MaxLgel]of longint; Euler:array[1..Maxel]of longint; f,g,h:array[0..Maxn]of int64; Vis:array[1..Maxn]of boolean; Root,Tot,Cnt,n,q,All,Order:longint; procedure Insert(x,y,z:longint); begin inc(Tot); Tov[Tot]:=y; Len[Tot]:=z; Next[Tot]:=Last[x]; Last[x]:=Tot; end; procedure Add(x,y,z:longint); begin Corefa[y]:=x; Orig[y]:=z; inc(Cnt); Aim[Cnt]:=y; Prev[Cnt]:=First[x]; First[x]:=Cnt; end; function Core(p:longint):longint; var i,x,y,Head,Tail,Temp,Sum,Key:longint; begin Head:=0; Tail:=1; Que[1]:=p; Size[p]:=0; Invfa[p]:=0; repeat inc(Head); x:=Que[Head]; i:=Last[x]; while i<>0 do begin y:=Tov[i]; if not Vis[y] and (y<>Invfa[x]) then begin inc(Tail); Que[Tail]:=y; Size[y]:=1; Invfa[y]:=x; end; i:=Next[i]; end; until Head=Tail; for i:=Tail downto 2 do begin x:=Que[i]; inc(Size[Invfa[x]],Size[x]); end; Key:=Maxlongint; Sum:=Size[p]; for Head:=1 to Tail do begin x:=Que[Head]; i:=Last[x]; Temp:=0; while i<>0 do begin y:=Tov[i]; if not Vis[y] and (y<>Invfa[x]) then if Size[y]>Temp then Temp:=Size[y]; i:=Next[i]; end; if Sum-Size[x]>Temp then Temp:=Sum-Size[x]; if Key>Temp then begin Key:=Temp; Core:=x; end; end; end; function Build(x:longint):longint; var i,y:longint; begin y:=Core(x); x:=y; Vis[x]:=true; i:=Last[x]; while i<>0 do begin y:=Tov[i]; if not Vis[y] then Add(x,Build(y),y); i:=Next[i]; end; exit(x); end; procedure Dfs(x,La:longint); var i,y:longint; begin inc(Order); Euler[Order]:=x; App[x]:=Order; i:=Last[x]; while i<>0 do begin y:=Tov[i]; if y<>La then begin High[y]:=High[x]+1; Up[y]:=Up[x]+Len[i]; Dfs(y,x); inc(Order); Euler[Order]:=x; end; i:=Next[i]; end; end; procedure Rmq_Preparation; var i,j,Lgel:longint; begin Lgel:=trunc(ln(Order)/ln(2)); for i:=1 to Order do Rmq[i,0]:=Euler[i]; for j:=1 to Lgel do for i:=1 to Order-1<<j+1 do if High[Rmq[i,j-1]]<High[Rmq[i+1<<(j-1),j-1]] then Rmq[i,j]:=Rmq[i,j-1] else Rmq[i,j]:=Rmq[i+1<<(j-1),j-1]; end; procedure Preparation; begin fillchar(Vis,sizeof(Vis),0); Root:=Build(1); High[1]:=1; Order:=0; Dfs(1,0); Rmq_Preparation; end; procedure Scanf; var i,x,y,z:longint; begin assign(input,'tree.in'); reset(input); readln(n,q); for i:=1 to n-1 do begin readln(x,y,z); Insert(x,y,z); Insert(y,x,z); end; Preparation; end; function LCA(x,y:longint):longint; var Rlg:longint; begin x:=App[x]; y:=App[y]; if x>y then begin x:=x xor y; y:=x xor y; x:=x xor y; end; Rlg:=trunc(ln(y-x+1)/ln(2)); if High[Rmq[x,Rlg]]<High[Rmq[y-1<<Rlg+1,Rlg]] then exit(Rmq[x,Rlg]) else exit(Rmq[y-1<<Rlg+1,Rlg]); end; function Dist(x,y:longint):longint; begin exit(Up[x]+Up[y]-Up[LCA(x,y)]<<1); end; function Dynamic_Core(p:longint):longint; var i,y,Lag,Total:longint; Flag:boolean; begin Flag:=true; i:=First[p]; while i<>0 do begin y:=Aim[i]; Flag:=Flag and (f[y]<<1<=All); i:=Prev[i]; end; if Flag then exit(p); Lag:=0; i:=First[p]; while i<>0 do begin y:=Aim[i]; if f[Lag]<f[y] then Lag:=y; i:=Prev[i]; end; Total:=f[p]-f[Lag]; y:=Orig[Lag]; while y<>p do begin inc(f[y],Total); y:=Corefa[y]; end; i:=Dynamic_Core(Lag); y:=Orig[Lag]; while y<>p do begin dec(f[y],Total); y:=Corefa[y]; end; exit(i); end; procedure Solve; var x,y,p,La:longint; l:int64; begin assign(output,'tree.out'); rewrite(output); All:=0; while q>0 do begin readln(x,y); inc(All,y); l:=0; p:=x; while p<>0 do begin inc(f[p],y); inc(g[p],l); if Corefa[p]<>0 then l:=int64(y)*Dist(x,Corefa[p]); inc(h[p],l); p:=Corefa[p]; end; x:=Dynamic_Core(Root); l:=0; La:=0; p:=x; while p<>0 do begin inc(l,g[p]); inc(l,int64(f[p]-f[La])*Dist(p,x)); if Corefa[p]<>0 then dec(l,h[p]); La:=p; p:=Corefa[p]; end; writeln(l); dec(q); end; close(input); close(output); end; begin Scanf; Solve; end.