点分治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和孩子们决定在家里玩捉 ...
随机推荐
- zoj 2949 - Coins of Luck
题目:有2中面条各n碗.每次抛硬币推断吃哪一种(到一种吃完为止).问抛硬币的数学期望. 分析:动态规划.概率dp.求出每种结束状态(即,有一种吃完)的概率,分别乘以步长即为期望. 大黄解法:状态位剩余 ...
- JOB Hunting 总结-----2013-11-5
从9月份开始的找工作大战,告一段落:其实早在10月中旬就已搞定,现在回想起这过去的几个月,很充实,很疲惫,很挫败又很有成就感! 开始找工作,对未来有过很多憧憬,也很迷茫,不知道自己的未来会在 ...
- python sax解析xml
#books.xml<catalog> <book isbn="0-596-00128-2"> <title>Python & XML& ...
- Map输出数据的处理类MapOutputBuffer分析
MapOutputBuffer顾名思义就是Map输出结果的一个Buffer,用户在编写map方法的时候有一个参数OutputCollector: void map(K1 key, V1 value, ...
- Codeforces 467D Fedor and Essay bfs
题目链接: 题意: 给定n个单词. 以下有m个替换方式.左边的单词能变成右边的单词. 替换随意次后使得最后字母r个数最少,在r最少的情况下单词总长度最短 输出字母r的个数和单词长度. 思路: 我们觉得 ...
- 【demo练习三】:图片水平滚动、点击按钮变更图片动画
要求:四张图片水平滚动,每隔5秒进行一次循环,点击按钮随机变更图片. XAML前台代码: <Window x:Class="图片滚动.MainWindow" xmlns=&q ...
- ASP.NET动态网站制作(12)-- JQ(4)
前言:这节课接着上次课的继续讲. 内容:接上--> 1.jq元素样式设置: (4)某个元素中是否含有某个css类别,返回布尔型:$("li:last").hasClass( ...
- Mybatis之基本简介
一.Mybatis简介 MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的JDBC代码.手工设置参数和结果集重获.MyBatis 只使用简单的XML ...
- php总结3——基本函数、流程控制中的循环
3.1 php基本函数(数学.日期.字符串) 数学函数:max mixed max(number $arg1,number $arg2,……) 求一组数据中的最大值 m ...
- 相比ICO,DAICO主要有这两方面优势
都说ICO已死,很有一部分人对无币区块链持保留态度,自从V神提出DAICO一来,大家似乎看到了新的方向,不少项目围绕其展开.那对比ICO,DAICO有哪些优势呢?主要是以下两点: DAICO维护了投资 ...