蒟蒻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

点分治Day2 动态树分治的更多相关文章

  1. COJ 0346 WZJ的旅行(二)更新动态树分治版本

    WZJ的旅行(二) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 时隔多日,WZJ又来到了幻想国旅行.幻想国由N个城市组成,由 ...

  2. 【Learning】 动态树分治

    简介 动态树分治整体上由点分治发展而来. 点分治是统计树上路径,而动态树分治用来统计与点有关的树上路径,比如多次询问某一些点到询问点的距离和. 前置知识就是点分治. 做法 众所周知,点分树(点分治中重 ...

  3. 【xsy2818】 最近点 动态树分治+可持久化线段树

    题目大意:给你一颗n个节点的树,最初点集S为空. 有m次操作:往当前点集S中加入/删除一个点,询问点x至集合S中任意点的最小距离,回到第t次修改点集的操作后的状态. 数据范围:$n,m≤10^5$ 我 ...

  4. 【BZOJ3730】震波 动态树分治+线段树

    [BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土 ...

  5. 洛谷P4719 【模板】"动态 DP"&动态树分治

    [模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...

  6. 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)

    [BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...

  7. 【BZOJ4372】烁烁的游戏 动态树分治+线段树

    [BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...

  8. 【BZOJ4317】Atm的树 动态树分治+二分+线段树

    [BZOJ4317]Atm的树 Description Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径 ...

  9. 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

随机推荐

  1. Excel工作表忘记密码如何破解?

    第一种方法就是按住快捷键ALT+F11,然后切换出VBA编辑窗口,如图一:在该窗口的左侧我们的选择那个忘记密码的工作表,比如sheet 1... 2 然后我们复制以下代码 “Sub Pojie()Ac ...

  2. QTreeWidget 的用法

    Qt QTreeWidget 新建一个Qt Widgets Application,拖拽一个Tree Widget 到 ui 界面上,最后实现的效果如下: 添加代码 //test.h //在头文件里添 ...

  3. Controller层返回字符串

    刚开始练习,有时候想让Controller层返回一个字符串,但是他却去寻找这个字符串名字的jsp页面,结果肯定会是404的,研究了一会才明白过来,如果Controller需要返回一个值的话,需要再方法 ...

  4. 解决Linux中文环境下astro和Calibre不能输入的问题

    例如我的opensuse在中文环境下不能在astro中输入指令,Calibre的grid spacing设置框不能输入,经过摸索,找到以下两种解决方法: 1.    将系统环境变成英文,在.bashr ...

  5. Linux kernel 2.6下的modules编译与KBuild

    转载:http://blog.sina.com.cn/s/blog_602f87700100dq1u.html Sam之前在Linux kernel 2.4下写过一些driver.但自从转到kerne ...

  6. HTML中Select的使用详解

    <html><head><SCRIPT LANGUAGE="JavaScript"><!--//oSelect 列表的底部添加了一个新选项 ...

  7. 【Android】带底部指示的自定义ViewPager控件

    在项目中经常需要使用轮转广告的效果,在android-v4版本中提供的ViewPager是一个很好的工具,而一般我们使用Viewpager的时候,都会选择在底部有一排指示物指示当前显示的是哪一个pag ...

  8. Android-解决Fail to post notification on channel "null"的方法

    原文:https://blog.csdn.net/weixin_40604111/article/details/78674563 在sdk版本为25或25之前想在notification中添加一个点 ...

  9. Android-Android Studio 3.0找不到Android Device Monitor

    原文:https://blog.csdn.net/yuanxiang01/article/details/80494842?utm_source=copy   为什么Android Studio 3. ...

  10. EasyNVR RTSP转RTMP-HLS流媒体服务器前端构建之_关于接口调用常见的一些问题(401 Unauthorized)

    在之前的博客<EasyNVR H5流媒体服务器方案架构设计之视频能力平台>中我们描述了EasyNVR的定位,作为一个能力平台来进行功能的输出: 也就是说,在通常情况下,我们将一套视频的应用 ...