蒟蒻Ez3real冬令营爆炸之后滚回来更新blog...

我们看一道题

bzoj3924

ZJOI2015D1T1 幻想乡战略游戏

给一棵$n$个点的树$(n \leqslant 150000)$ 点上有点权 边上有边权

每个点度数不大于$20$

你需要放置一个补给站 补给站供给某个点的代价等于它们之间路径长度 $\cdot$ 那个点的点权

供给整张图的代价为供给每个点的代价之和

即:如供给站在$u$,每个点的点权为 $d_{v_{i}}$

则总代价为 $$ \sum_{i=1}^{n}  d_{v_{i}} \cdot dist(u,v_{i})$$

每次操作更改一个点的点权

每次更改后可以选一个位置放补给站 你需要求出供给整张图代价最小值

(每次改点权 询问树上带权重心)

如果没有修改操作,就是我们曾经研究过的树上路径问题,可以用点分治水过去

现在带修改,于是我们考虑:动态树分治

动态树分治又称点分树 是把树用数据结构维护的一种方法

与点分治一样地 我们找到每个子树的重心来构建这颗树

每层重心构成一个树形结构

我们在这个树形结构上跑数据结构就可以咯

具体地

首先我们可以先用树分治构建出这棵树的分治树,也就是把这棵树的重心作为根节点然后子树为他的子树的重心这样递归下去,然后每个节点存的是其子树的信息。

对于每个节点我们保存这个子树的$d_{v}$的总和已经把该节点作为点的答案值

这样对于修改能在$log_2n$的时间内解决

寻找答案的时候,我们可以发现,如果现在节点的子树$\sum d_{v_{i}}$大于总节点,那么向那个方向过去一定比原方案好

我们先从根节点开始,若发现答案在某棵子树时,我们考虑如何使其儿子节点的答案转变为整个树的答案,可以发现把除这个子树外的所有节点可以缩成一个节点并连在这棵子树上,然后就可以一直这样做下去,找到操作之后再把这些撤销

因此还是得维护一些奇奇怪怪的东西,但打出来还是挺短的

#include<bits/stdc++.h>
#define LL long long
const int maxn = ;
using namespace std;
int m,n;
int first[maxn],to[maxn],next[maxn],val[maxn],cnt;
inline void add(int u,int v,int w)
{
to[++cnt]=v;
val[cnt]=w;
next[cnt]=first[u];
first[u]=cnt;
}
int dep[maxn],dis[maxn],fat[maxn][],s[maxn];
int id[maxn],ip[maxn],top;
void dfs(int u,int fa)
{
s[++top]=u;
if(!id[u])id[u]=top;
dep[top]=dep[ip[fa]]+;ip[u]=top;
for(int i=first[u];i;i=next[i])
{
int v=to[i];
if(v==fa)continue;
dis[v]=dis[u]+val[i];
dfs(v,u);s[++top]=u;dep[top]=dep[ip[fa]+];
}
}
void make()
{
for(int i=;i<=top;i++) fat[i][]=i;
for(int j=;j<=;j++)
for(int i=;i<=top;i++)
if(i+(<<j)-<=top)
{
int x=fat[i][j-],y=fat[i+(<<j-)][j-];
if(dep[fat[i][j-]]<dep[fat[i+(<<j-)][j-]]) fat[i][j]=fat[i][j-];
else fat[i][j]=fat[i+(<<j-)][j-];
}
}
inline int query(int l,int r)
{
int len=r-l+,k=;
for(k=;<<k+<=len;k++);
if(dep[fat[l][k]]<dep[fat[r-(<<k)+][k]])return fat[l][k];
else return fat[r-(<<k)+][k];
}
inline int lca(int u,int v)
{
if(id[u]>id[v]) swap(u,v);
return s[query(id[u],id[v])];
}
inline int caldis(int u,int v)
{
int LCA=lca(u,v);
return dis[u]+dis[v]-*dis[LCA];
}
int rt,sum,f[maxn],size[maxn],vis[maxn];
inline void GetRT(int x,int fa)
{
size[x]=;f[x]=;
for(int i=first[x];i;i=next[i])
{
if(to[i]==fa || vis[to[i]])continue;
GetRT(to[i],x);size[x]+=size[to[i]];
f[x]=max(f[x],size[to[i]]);
}
f[x]=max(f[x],sum-size[x]);
if(f[x]<f[rt])rt=x;
}
int ret,dv[maxn],par[maxn];
LL ans[maxn],anss[maxn],summ[maxn];
inline void work(int x)
{
vis[x]=;summ[x]=ret;
for(int i=first[x];i;i=next[i])
{
if(vis[to[i]])continue;
rt=,sum=size[to[i]];
GetRT(to[i],);
par[rt]=x;work(rt);
}
}
LL cal(int u)
{
LL ret=ans[u];
for(int i=u;par[i];i=par[i])
{
LL delt=caldis(par[i],u);
ret+=(ans[par[i]]-anss[i]);
ret+=delt*(summ[par[i]]-summ[i]);
}
return ret;
}
LL update(int u,int va)
{
summ[u]+=va;
for(int i=u;par[i];i=par[i])
{
LL di=caldis(par[i],u);
summ[par[i]]+=va;
anss[i]+=va*di;
ans[par[i]]+=va*di;
}
}
int last=;
LL query(int u)
{
LL ka=cal(u);
for(int i=first[u];i;i=next[i])
{
LL tmp=cal(to[i]);
if(tmp < ka)return query(to[i]);
}
last=u;
return ka;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}top=,dfs(,);
//cout<<top<<endl;
make();sum=f[]=n;GetRT(,);
work(rt);
for(int i=;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
update(a,b);
printf("%lld\n",query(last));
}
}

习题:bzoj3924  bzoj1095  bzoj4012

最新文章

  1. Oracle基础——学习笔记
  2. yii2 随笔
  3. C# 五、谈扩展方法的理解
  4. 虚拟现实外包公司— VR开发编辑器意义重大 印证VR不仅服务于用户
  5. [poj2406] Power Strings
  6. srcolltop 的用法
  7. 两个实用的Python的装饰器
  8. C语言 结构体数组保存到二进制文件中
  9. [转]Delphi中QuotedStr介绍及使用
  10. win10 uwp 绑定静态属性
  11. [LeetCode] Asteroid Collision 行星碰撞
  12. java.lang.NumberFormatException: For input string: &quot; &quot;
  13. tuxedo开发
  14. UVA10720 Graph Construction 度序列可图性
  15. abap函数返回结构体类型
  16. js获取url传递得参数
  17. 性能测试-10.数据分析Analysis
  18. vue滚动行为控制——页面跳转返回上一个页面保留滚动位置
  19. STAF进行分布式脚本分发----实践篇
  20. Selenium - Xpath 使用方法

热门文章

  1. HPE IT 的DevOps 实践分享
  2. node.js ----NPM使用介绍
  3. Android 开源项目精选
  4. Cookie的写入,和读取
  5. MP4文件格式的解析,以及MP4文件的分割算法
  6. jquery插件函数传参错误
  7. Chrome自带恐龙小游戏的源码研究(六)
  8. js关于变量作为if条件的真假问题
  9. Erlang的系统限制
  10. windows 2008配置运行PHP5.5.X