传送门

考虑先随便找一个点作为根,然后再慢慢移动根,这样一步步走到最优的点

设 $sum[x]$ 表示节点 $x$ 的子树的军队数,$len(x,y)$ 表示 $x,y$ 之间边的长度

那么对于根节点 $x$ 的一个儿子 $v$,考虑把儿子搞为根时,代价的改变量

$v$ 的子树内的军队消耗减少,共减少了 $sum[v]\cdot len(x,v)$

$v$ 的子树外的军队消耗增加,即根节点 $x$ 的子树内除了 $v$ 子树的军队消耗增加

代价增加了 $(sum[x]-sum[v])\cdot len(x,y)$

如果儿子比父亲优,那么整理可得 $2sum[v]>sum[x]$,显然满足条件的 $v$ 只有一个

此时如果没有满足的 $v$ ,那么 $x$ 就是最优点,否则最优点在 $x$ 的子树内

如果每次都一个一个儿子跳下去,显然会GG

但是因为最优点在子树内所以可以考虑在点分树上跳

我们需要维护两个东西 : $S[x],Sf[x]$,分别表示节点 $x$的点分树子树到 $x$ 的总代价,节点 $x$ 的点分树子树到 $x$ 在点分树父亲 $Fa[x]$ 的总代价

那么计算一个节点 $x$ 的总消耗就考虑一直往 $Fa$ 跳,每次跳完就考虑这一段产生的代价

设当前跳到了节点 $now$

那么十分显然 $Fa[now]$ 的点分树子树 不包括 $now$ 的点分树子树 的部分新产生的代价为 $S[Fa[now]]-Sf[now]+(sum[Fa[now]]-sum[now])\cdot dis(Fa[now],x)$

($dis(x,y)$表示节点 $x,y$ 在原树上的距离,注意此时 $sum[x]$ 表示节点 $x$ 的点分树子树军队总数)

我们可以用 RMQ 求 LCA 来 $O(1)$ 求出两点间的距离

至于修改操作也在点分树上直接维护就好了

注意$long long$,代码有注释

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e5+,INF=1e9+;
int fir[N],from[N],to[N],val[N],cntt;
inline void add(int &a,int &b,int &c)
{
from[++cntt]=fir[a]; fir[a]=cntt;
to[cntt]=b; val[cntt]=c;
}
int n,m,tot,rt;
int sz[N],mx[N],Fa[N];
vector <int> V[N],G[N];//存点分树
bool vis[N];
void find_rt(int x,int fa)
{
sz[x]=; mx[x]=;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==fa||vis[v]) continue;
find_rt(v,x); sz[x]+=sz[v];
mx[x]=max(mx[x],sz[v]);
}
mx[x]=max(mx[x],tot-sz[x]);
if(mx[x]<mx[rt]) rt=x;
}
void build(int x)//建点分树
{
vis[x]=;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(vis[v]) continue;
tot=sz[v]; rt=; find_rt(v,);
V[x].push_back(rt); G[x].push_back(v);
Fa[rt]=x; build(rt);
}
}
int st[N],dfn[N],pos[N],dis[N],Top,dfs_clock,f[N][],Log[N];//维护RMQ求LCA维护dis
void dfs(int x,int fa)
{
dfn[x]=++dfs_clock; st[++Top]=x; pos[x]=Top;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==fa) continue;
dis[v]=dis[x]+val[i]; dfs(v,x);
st[++Top]=x;
}
}
void pre()
{
Log[]=-; for(int i=;i<=Top;i++) Log[i]=Log[i>>]+;
for(int i=;i<=Top;i++) f[i][]=st[i];
for(int i=;(<<i)<=Top;i++)
for(int j=;j+(<<i-)<=Top;j++)
{
if(dfn[f[j][i-]]<dfn[ f[j+(<<i-)][i-] ]) f[j][i]=f[j][i-];
else f[j][i]=f[j+(<<i-)][i-];
}
}
inline int LCA(int x,int y)
{
int l=pos[x],r=pos[y]; if(l>r) swap(l,r);
int k=Log[r-l+];
if(dfn[f[l][k]]<dfn[f[r-(<<k)+][k]]) return f[l][k];
return f[r-(<<k)+][k];
}
inline int Dis(int x,int y) { return dis[x]+dis[y]-*dis[LCA(x,y)]; }
ll sum[N],S[N],Sf[N];//注意long long
inline void change(int x,int y)//修改操作
{
sum[x]+=y;
for(int now=x;Fa[now];now=Fa[now])//在点分树上跳
{
int d=Dis(x,Fa[now]);
Sf[now]+=1ll*d*y;
S[Fa[now]]+=1ll*d*y;
sum[Fa[now]]+=y;
}
}
inline ll calc(int x)//计算以x为根的花费
{
ll res=S[x];
for(int now=x;Fa[now];now=Fa[now])
{
int d=Dis(x,Fa[now]);
res+=S[Fa[now]]-Sf[now]+(sum[Fa[now]]-sum[now])*d;
}
return res;
}
ll query(int x)//点分树上暴力dfs找最优解
{
ll res=calc(x); int len=V[x].size();
for(int i=;i<len;i++)
{
ll t=calc(G[x][i]);//注意是算G[x][i]
if(t<res) return query(V[x][i]);//注意是往V[x][i]跳
}
return res;
}
int main()
{
int a,b,c,RT;
n=read(); m=read();
for(int i=;i<n;i++)
{
a=read(),b=read(),c=read();
add(a,b,c); add(b,a,c);
}
tot=n; mx[]=INF;
find_rt(,); RT=rt; build(rt);
dfs(,); pre();
while(m--)
{
a=read(); b=read();
change(a,b);
printf("%lld\n",query(RT));
}
return ;
}

最新文章

  1. Python之路【第二篇】python基础 之基本数据类型
  2. POJ 3728
  3. Tomcat不能自动编译JSP文件问题的一种解决方法
  4. ■Ascii逐字解码法注入,mysql5.0一下版本手工注入
  5. [原]Hrbust1328 相等的最小公倍数 (筛素数,素因子分解)
  6. Soy文件生成JS文件 - 一个使用Google soy模板的例子
  7. Leetcode_Best Time to Buy and Sell Stock
  8. 【亲测】Appium测试Android混合应用时,第二次切换到WebView失败
  9. 全面总结: Golang 调用 C/C++,例子式教程
  10. ABP文档笔记 - 通知
  11. git的撤销动作
  12. Python机器学习(基础篇---监督学习(朴素贝叶斯))
  13. [leetcode]92. Reverse Linked List II反转链表2
  14. Kali学习笔记20:缓冲区溢出实验环境准备
  15. LOJ#6285. 数列分块入门 9
  16. python之 协程
  17. xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at[转载]
  18. CentOS 安装apache
  19. visual studio 2017 报错 无法下载安装文件。请检查Internet连接,然后重试
  20. Android DiskLruCache完全解析,硬盘缓存的最佳方案

热门文章

  1. cocos2d-x 在vs2010下的搭建(win7系统)
  2. SQL Server 索引维护:系统常见的索引问题
  3. 微信WeixinJSBridge API 屏蔽右上角分享等常用方法
  4. xamarin.droid自己的示例工程有些都装不上模拟器,是因为它的architectures选项没设对
  5. 推荐一款基于XNA的开源游戏引擎《Engine Nine》
  6. 利用Thread.stop完成方法执行超时中断
  7. repo相关命令
  8. 数据库去重与join连表
  9. delphi 取json中数组的值(ISuperArray)
  10. Sql Server 日期格式化函數 Convert