[Luogu3345][ZJOI2015]幻想乡战略游戏
Luogu
题意:
动态维护带权重心。
sol
这是一道写起来很舒服的动态点分治。(不像某些毒瘤题)
我们考虑,如果你选择的补给点不是当前的带权重心,那么带权重心就在补给点的一个子树中(你把补给点当做根的话)。那么,你把补给点向带权重心所在的子树中移动的时候,答案一定会减小。换言之,如果补给点无论向哪个方向移动答案都不会减小,那么这个点就是带权重心。
所以我们每次考虑移动补给点然后计算即可。
但是怎么移动呢?
最优复杂度的移动策略是:先假设点分树的根就是补给,然后你一次检查与它在原树中相连的所有点,如果有一个比它小(这样的点至多有一个),这时候你不是直接跳向这个点,而是跳向点分树中的那个儿子。这样在保证了解的范围的同时也保证了复杂度,因为点分树的树高是\(\log n\),所以最多向下跳\(\log n\)
次。
主题思想解决了,现在我们考虑怎么快速计算出以某一个点为补给点时的答案。
我们记一下三个变量(不要吐槽变量名):
\(sum_i\):表示点分树中以i为根的子树的权值和
\(gather_i\):表示点分树中以i为根的子树全部集合到i的总耗费
\(tofa_i\)表示点分树中以i为根的子树全部集合到i在点分树中的父节点的总耗费
可以发现其实\(gather_u=\sum tofa_v\),其中v是u在点分树中的儿子。之所以这样记是为了去除重复计算。
具体怎么算请自行YY。(YY有益身心健康)
总的算起来复杂度是\(O(n\log^3n)\)(但显然不满的),如果你写\(RMQLCA\)的话就是\(O(n\log^2n)\)
code
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100005;
#define ll long long
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
int n,m,dis[N],sum[N];
ll gather[N],tofa[N];
struct edge{int to,next,w;}a[N<<1];
int head[N],cnt,pa[N],dep[N],sz[N],son[N],top[N];
void dfs1(int u,int f)
{
	pa[u]=f;dep[u]=dep[f]+1;sz[u]=1;
	for (int e=head[u];e;e=a[e].next)
	{
		int v=a[e].to;if (v==f) continue;
		dis[v]=dis[u]+a[e].w;dfs1(v,u);
		sz[u]+=sz[v];if (sz[v]>sz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int up)
{
	top[u]=up;
	if (son[u]) dfs2(son[u],up);
	for (int e=head[u];e;e=a[e].next)
		if (a[e].to!=pa[u]&&a[e].to!=son[u])
			dfs2(a[e].to,a[e].to);
}
int lca(int u,int v)
{
	while (top[u]^top[v])
	{
		if (dep[top[u]]<dep[top[v]]) swap(u,v);
		u=pa[top[u]];
	}
	return dep[u]<dep[v]?u:v;
}
int getdis(int u,int v){return dis[u]+dis[v]-2*dis[lca(u,v)];}
struct node{int to,next,rt;}G[N];
int vis[N],w[N],fa[N],root,tot,RT,ft[N];
void getroot(int u,int f)
{
	sz[u]=1;w[u]=0;
	for (int e=head[u];e;e=a[e].next)
	{
		int v=a[e].to;if (v==f||vis[v]) continue;
		getroot(v,u);
		sz[u]+=sz[v];w[u]=max(w[u],sz[v]);
	}
	w[u]=max(w[u],tot-sz[u]);
	if (w[u]<w[root]) root=u;
}
void solve(int u,int f)
{
	fa[u]=f;vis[u]=1;int pre_tot=tot;
	for (int e=head[u];e;e=a[e].next)
	{
		int v=a[e].to;if (vis[v]) continue;
		if (sz[v]>sz[u]) tot=pre_tot-sz[u];
		else tot=sz[v];
		root=0;
		getroot(v,0);
		G[++cnt]=(node){v,ft[u],root};ft[u]=cnt;
		solve(root,u);
	}
}
void Modify(int u,int val)
{
	sum[u]+=val;
	for (int i=u;fa[i];i=fa[i])
	{
		int dist=getdis(u,fa[i]);
		sum[fa[i]]+=val;
		gather[fa[i]]+=(ll)val*dist;
		tofa[i]+=(ll)val*dist;
	}
}
ll calc(int u)
{
	ll res=gather[u];
	for (int i=u;fa[i];i=fa[i])
	{
		int dist=getdis(u,fa[i]);
		res+=(ll)(sum[fa[i]]-sum[i])*dist;
		res+=gather[fa[i]]-tofa[i];
	}
	return res;
}
ll Query(int u)
{
	ll temp=calc(u);
	for (int e=ft[u];e;e=G[e].next)
		if (calc(G[e].to)<temp) return Query(G[e].rt);
	return temp;
}
int main()
{
	n=gi();m=gi();
	for (int i=1;i<n;i++)
	{
		int u=gi(),v=gi(),w=gi();
		a[++cnt]=(edge){v,head[u],w};head[u]=cnt;
		a[++cnt]=(edge){u,head[v],w};head[v]=cnt;
	}
	dfs1(1,0);dfs2(1,1);
	w[0]=tot=n;cnt=0;
	getroot(1,0);
	RT=root;
	solve(root,0);
	while (m--)
	{
		int u=gi(),e=gi();
		Modify(u,e);
		printf("%lld\n",Query(RT));
	}
	return 0;
}
[Luogu3345][ZJOI2015]幻想乡战略游戏的更多相关文章
- 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告
		P3345 [ZJOI2015]幻想乡战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做 ... 
- [ZJOI2015]幻想乡战略游戏——动态点分治
		[ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ... 
- BZOJ3924 ZJOI2015 幻想乡战略游戏 【动态点分治】
		BZOJ3924 ZJOI2015 幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂 ... 
- AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345
		[ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ... 
- 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治
		[BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ... 
- bzoj3924 [Zjoi2015]幻想乡战略游戏 点分树,动态点分
		[BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ... 
- BZOJ3924 [Zjoi2015]幻想乡战略游戏
		Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ... 
- [ZJOI2015]幻想乡战略游戏
		Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ... 
- bzoj 3924: [Zjoi2015]幻想乡战略游戏
		Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ... 
随机推荐
- Docker命令行安装Shipyard
			1.下载自动部署Shell脚本 curl -sSL https://shipyard-project.com/deploy | bash -s 自动部署脚本中, 包括以下参数: ACTION: 表示可 ... 
- 关于Apache配置虚拟主机后在局域网中让其他电脑访问
			#-----------adxssp------------# NameVirtualHost *:80 <VirtualHost *:80> ServerName www.b.com D ... 
- iOS7控制中心会覆盖由下向上的手势
			Expect users to swipe up from the bottom of the screen to reveal Control Center. If iOS determines t ... 
- 洛谷P2891 Dining P1402 酒店之王【类二分图匹配】题解+代码
			洛谷P2891 Dining P1402 酒店之王[类二分图匹配]题解+代码 酒店之王 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的 ... 
- 利用ajax获取网页表单数据,并存储到数据库之二(使用SSH)
			上篇介绍了如何使用JDBC链接ORACLE数据库实现对数据库的增删改查,本例是使用框架SSH来对数据库的数据进行操作. 首先说框架,现在流行的框架很多,如Struts.Hibernate.Spring ... 
- datatables行编辑中,某个字段用户显示和用于行编辑名称不同时的处理。
			比如tag这个字段,对应服务端bean的tag,但是在页面显示时需要为String类型的tagName,那么在行编辑时可以用以下的方式处理. 
- C++11 左值、右值、右值引用详解
			C++11 左值.右值.右值引用详解 左值.右值 在C++11中所有的值必属于左值.右值两者之一,右值又可以细分为纯右值.将亡值. 在C++11中可以取地址的.有名字的就是左值,反之,不能取地址的.没 ... 
- ubuntu16.04编译安装mysql-boost-5.7.21并编译成php扩展测试与使用
			我之前的文章已经改造了自定义MVC框架中的工具类(验证码,图片上传,图像处理,分类)4个类,接下来,就要改造模型类,模型类肯定要连接数据库,由于我的Ubuntu Linux是裸装的php(目前只编译了 ... 
- 编码问题 php字符编码转换类
			各种平台和软件打开显示的编码问题,需要使用不同的编码,根据我们不同的需求. php 字符编码转换类,支持ANSI.Unicode.Unicode big endian.UTF-8.UTF-8+Bom ... 
- chrome使用Timeline做性能分析
			使用Timeline做性能分析 Timeline面板记录和分析了web应用运行时的所有活动情况,这是研究和查找性能问题的最佳途径.###Timeline面板概览 Timeline面板主要有三个部分构成 ... 
