P3345 [ZJOI2015]幻想乡战略游戏
考虑先随便找一个点作为根,然后再慢慢移动根,这样一步步走到最优的点
设 $sum[x]$ 表示节点 $x$ 的子树的军队数,$len(x,y)$ 表示 $x,y$ 之间边的长度
那么对于根节点 $x$ 的一个儿子 $v$,考虑把儿子搞为根时,代价的改变量
$v$ 的子树内的军队消耗减少,共减少了 $sum[v]\cdot len(x,v)$
$v$ 的子树外的军队消耗增加,即根节点 $x$ 的子树内除了 $v$ 子树的军队消耗增加
代价增加了 $(sum[x]-sum[v])\cdot len(x,y)$
如果儿子比父亲优,那么整理可得 $2sum[v]>sum[x]$,显然满足条件的 $v$ 只有一个
此时如果没有满足的 $v$ ,那么 $x$ 就是最优点,否则最优点在 $x$ 的子树内
如果每次都一个一个儿子跳下去,显然会GG
但是因为最优点在子树内所以可以考虑在点分树上跳
我们需要维护两个东西 : $S[x],Sf[x]$,分别表示节点 $x$的点分树子树到 $x$ 的总代价,节点 $x$ 的点分树子树到 $x$ 在点分树父亲 $Fa[x]$ 的总代价
那么计算一个节点 $x$ 的总消耗就考虑一直往 $Fa$ 跳,每次跳完就考虑这一段产生的代价
设当前跳到了节点 $now$
那么十分显然 $Fa[now]$ 的点分树子树 不包括 $now$ 的点分树子树 的部分新产生的代价为 $S[Fa[now]]-Sf[now]+(sum[Fa[now]]-sum[now])\cdot dis(Fa[now],x)$
($dis(x,y)$表示节点 $x,y$ 在原树上的距离,注意此时 $sum[x]$ 表示节点 $x$ 的点分树子树军队总数)
我们可以用 RMQ 求 LCA 来 $O(1)$ 求出两点间的距离
至于修改操作也在点分树上直接维护就好了
注意$long long$,代码有注释
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e5+,INF=1e9+;
int fir[N],from[N],to[N],val[N],cntt;
inline void add(int &a,int &b,int &c)
{
from[++cntt]=fir[a]; fir[a]=cntt;
to[cntt]=b; val[cntt]=c;
}
int n,m,tot,rt;
int sz[N],mx[N],Fa[N];
vector <int> V[N],G[N];//存点分树
bool vis[N];
void find_rt(int x,int fa)
{
sz[x]=; mx[x]=;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==fa||vis[v]) continue;
find_rt(v,x); sz[x]+=sz[v];
mx[x]=max(mx[x],sz[v]);
}
mx[x]=max(mx[x],tot-sz[x]);
if(mx[x]<mx[rt]) rt=x;
}
void build(int x)//建点分树
{
vis[x]=;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(vis[v]) continue;
tot=sz[v]; rt=; find_rt(v,);
V[x].push_back(rt); G[x].push_back(v);
Fa[rt]=x; build(rt);
}
}
int st[N],dfn[N],pos[N],dis[N],Top,dfs_clock,f[N][],Log[N];//维护RMQ求LCA维护dis
void dfs(int x,int fa)
{
dfn[x]=++dfs_clock; st[++Top]=x; pos[x]=Top;
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==fa) continue;
dis[v]=dis[x]+val[i]; dfs(v,x);
st[++Top]=x;
}
}
void pre()
{
Log[]=-; for(int i=;i<=Top;i++) Log[i]=Log[i>>]+;
for(int i=;i<=Top;i++) f[i][]=st[i];
for(int i=;(<<i)<=Top;i++)
for(int j=;j+(<<i-)<=Top;j++)
{
if(dfn[f[j][i-]]<dfn[ f[j+(<<i-)][i-] ]) f[j][i]=f[j][i-];
else f[j][i]=f[j+(<<i-)][i-];
}
}
inline int LCA(int x,int y)
{
int l=pos[x],r=pos[y]; if(l>r) swap(l,r);
int k=Log[r-l+];
if(dfn[f[l][k]]<dfn[f[r-(<<k)+][k]]) return f[l][k];
return f[r-(<<k)+][k];
}
inline int Dis(int x,int y) { return dis[x]+dis[y]-*dis[LCA(x,y)]; }
ll sum[N],S[N],Sf[N];//注意long long
inline void change(int x,int y)//修改操作
{
sum[x]+=y;
for(int now=x;Fa[now];now=Fa[now])//在点分树上跳
{
int d=Dis(x,Fa[now]);
Sf[now]+=1ll*d*y;
S[Fa[now]]+=1ll*d*y;
sum[Fa[now]]+=y;
}
}
inline ll calc(int x)//计算以x为根的花费
{
ll res=S[x];
for(int now=x;Fa[now];now=Fa[now])
{
int d=Dis(x,Fa[now]);
res+=S[Fa[now]]-Sf[now]+(sum[Fa[now]]-sum[now])*d;
}
return res;
}
ll query(int x)//点分树上暴力dfs找最优解
{
ll res=calc(x); int len=V[x].size();
for(int i=;i<len;i++)
{
ll t=calc(G[x][i]);//注意是算G[x][i]
if(t<res) return query(V[x][i]);//注意是往V[x][i]跳
}
return res;
}
int main()
{
int a,b,c,RT;
n=read(); m=read();
for(int i=;i<n;i++)
{
a=read(),b=read(),c=read();
add(a,b,c); add(b,a,c);
}
tot=n; mx[]=INF;
find_rt(,); RT=rt; build(rt);
dfs(,); pre();
while(m--)
{
a=read(); b=read();
change(a,b);
printf("%lld\n",query(RT));
}
return ;
}
P3345 [ZJOI2015]幻想乡战略游戏的更多相关文章
- 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告
P3345 [ZJOI2015]幻想乡战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做 ...
- P3345 [ZJOI2015]幻想乡战略游戏 动态点分治
\(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...
- 洛谷P3345 [ZJOI2015]幻想乡战略游戏 [动态点分治]
传送门 调了两个小时,终于过了-- 凭啥人家代码80行我180行啊!!! 谁叫你大括号换行 谁叫你写缺省源 思路 显然,补给点所在的位置就是这棵树的带权重心. 考虑size已知时如何找重心:一开始设答 ...
- 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)
洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...
- 2018.08.28 洛谷P3345 [ZJOI2015]幻想乡战略游戏(点分树)
传送门 题目就是要求维护带权重心. 因此破题的关键点自然就是带权重心的性质. 这时发现直接找带权重心是O(n)的,考虑优化方案. 发现点分树的树高是logn级别的,并且对于以u为根的树,带权重心要么就 ...
- BZOJ 3924 / Luogu P3345 [ZJOI2015]幻想乡战略游戏 (动态点分治/点分树)
题意 树的结构不变,每个点有点权,每一条边有边权,有修改点权的操作,设xxx为树中一点.求∑idist(x,i)∗a[i]\sum_idist(x,i)*a[i]i∑dist(x,i)∗a[i]的最 ...
- AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345
[ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...
- [ZJOI2015]幻想乡战略游戏——动态点分治
[ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...
- BZOJ3924 ZJOI2015 幻想乡战略游戏 【动态点分治】
BZOJ3924 ZJOI2015 幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂 ...
随机推荐
- c++策略模式(Strategy Method)
别人的博客再讲策略模式时都会讲三国,策略类就是赵云的锦囊,锦囊里装着若干妙计.在打仗时想要用什么妙计,直接从锦囊里去取. 锦囊类: class context { public: context(IS ...
- eclipse检测不到android的手机
eclipse检测不到android设备我们一般重启adb server但是一般不管用,下面是重启adb server adb kill-server 可能出现“服务没有运行”的提示信息如下: * s ...
- 利用arcgis实现经纬度和平面坐标互转
一平面直角坐标(投影坐标)转经纬度 基本程序是这样的 经纬度计算操作 1. 定义坐标系:在AreToolbox下→数据管理工具→投影和变换→定义投影→输入数据或要素点击▼选择定义同层(同时在坐标系中点 ...
- 复习扩展方法 涉及委托,这里我使用自定义委托类型 public delegate bb MyFunc<in T,out bb> (T arg)
using System;using System.Collections.Generic;using System.Data;using System.Linq;using System.Text; ...
- hdu 4741 Save Labman No.004 (异面直线的距离)
转载学习: #include <cstdio> #include <cstdlib> #include <cstring> #include <algorit ...
- 手打的table
突然觉得,如果我不上传源码和写篇博客,对不起花在这个破网页2个小时的时间,完全手打,浏览器调效果. 源码如下: a.html: <!DOCTYPE html PUBLIC "-//W3 ...
- servlet模板
package ${enclosing_package};import java.io.IOException;import javax.servlet.ServletException;import ...
- HDU 3723 Delta Wave (高精度+calelan数)
题意:给定一个图,问你只能向上向下,或者平着走,有多少种方法可以走到最后一个格. 析:首先先考虑,如果没有平的情况就是calelan数了,现在有平的情况,那么就枚举呗,因为数很大,所以要用高精度. 答 ...
- ArcGIS Engine 中对栅格数据的波段信息统计 (转)
先打开栅格文件所在的工作空间(文件),然后获取其所有的波段,访问每一个波段有时候波段中已经有直方图或统计信息,有时候没有这些信息,可以使用ComputeStatsAndHist()函数对其进行计算(数 ...
- OM—>AR相关会计科目
业务会计核算 挑库: 借:发出商品 (递延销货成本) 贷:发出商品 (递延销货成本) 发运: 借:发出商品 (递延销货成本) 贷:库存商品/原材料 (库存估 ...