点分治Day2 动态树分治
蒟蒻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 动态树分治的更多相关文章
- COJ 0346 WZJ的旅行(二)更新动态树分治版本
WZJ的旅行(二) 难度级别:D: 运行时间限制:3000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 时隔多日,WZJ又来到了幻想国旅行.幻想国由N个城市组成,由 ...
- 【Learning】 动态树分治
简介 动态树分治整体上由点分治发展而来. 点分治是统计树上路径,而动态树分治用来统计与点有关的树上路径,比如多次询问某一些点到询问点的距离和. 前置知识就是点分治. 做法 众所周知,点分树(点分治中重 ...
- 【xsy2818】 最近点 动态树分治+可持久化线段树
题目大意:给你一颗n个节点的树,最初点集S为空. 有m次操作:往当前点集S中加入/删除一个点,询问点x至集合S中任意点的最小距离,回到第t次修改点集的操作后的状态. 数据范围:$n,m≤10^5$ 我 ...
- 【BZOJ3730】震波 动态树分治+线段树
[BZOJ3730]震波 Description 在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i].不幸的是,这片土 ...
- 洛谷P4719 【模板】"动态 DP"&动态树分治
[模板]"动态 DP"&动态树分治 第一道动态\(DP\)的题,只会用树剖来做,全局平衡二叉树什么的就以后再学吧 所谓动态\(DP\),就是在原本的\(DP\)求解的问题上 ...
- 【BZOJ2001】[HNOI2010]城市建设(CDQ分治,线段树分治)
[BZOJ2001][HNOI2010]城市建设(CDQ分治,线段树分治) 题面 BZOJ 洛谷 题解 好神仙啊这题.原来想做一直不会做(然而YCB神仙早就切了),今天来怒写一发. 很明显这个玩意换种 ...
- 【BZOJ4372】烁烁的游戏 动态树分治+线段树
[BZOJ4372]烁烁的游戏 Description 背景:烁烁很喜欢爬树,这吓坏了树上的皮皮鼠.题意:给定一颗n个节点的树,边权均为1,初始树上没有皮皮鼠.烁烁他每次会跳到一个节点u,把周围与他距 ...
- 【BZOJ4317】Atm的树 动态树分治+二分+线段树
[BZOJ4317]Atm的树 Description Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
随机推荐
- Chrome自带恐龙小游戏的源码研究(五)
在上一篇<Chrome自带恐龙小游戏的源码研究(四)>中实现了障碍物的绘制及移动,从这一篇开始主要研究恐龙的绘制及一系列键盘动作的实现. 会眨眼睛的恐龙 在游戏开始前的待机界面,如果仔细观 ...
- Java中的Enum的继承
public interface Icolor{ int apply(int x,int y); } public enum color implements Icolor{ plus("+ ...
- 解决opencv无法读AVI视频的问题
原文来自:http://blog.csdn.net/yeqiu712/article/details/6220030 其实AVI只是一个外壳.里面的东西可不一样的! 问题:为什么我的电脑支持AVI或者 ...
- kvm&vnc 简单安装shell脚本
#!/bin/bash # created on 2014/7/15 #author : derrick.jiang (Email: derrick.jiang.maichuang.net) echo ...
- Codeforces Round #316 (Div. 2) (ABC题)
A - Elections 题意: 每一场城市选举的结果,第一关键字是票数(降序),第二关键字是序号(升序),第一位获得胜利. 最后的选举结果,第一关键字是获胜城市数(降序),第二关键字是序号(升序) ...
- rtmp直播拉流客户端EasyRTMPClient TCP窗口大小设计方法
EasyRTMPClient 简介 EasyRTMPClient是EasyDarwin流媒体团队开发.提供的一套非常稳定.易用.支持重连接的RTMPClient工具,以SDK形式提供,接口调用非常简单 ...
- Asp.net MVC3 异常全局过滤器处理
1.建立异常全局过滤器处理机制,在Gloabal.asax.cs文件中,有如下代码块: public static void RegisterGlobalFilters(GlobalFilterCol ...
- cocos2d-js添加百度MSSP插屏(通过jsb反射机制)
1.导入jar包.... 2.修改AndroidManifest.xml文件 添加: <meta-data android:name="BaiduMobAd_APP_ID" ...
- 题解 P1095 【守望者的逃离】
贪心.数组都不用开那种. 考虑跑步距离的构成.发现跑步只有三种情况构成 休息 传送 朴素地跑 显然,如果可以传送,我们就不要朴素地跑步.因为\(17\le 60 \div 2 =30\). 假如我们知 ...
- (转)js中__proto__和prototype的区别和关系
作者:doris链接:https://www.zhihu.com/question/34183746/answer/58155878来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...