传送门

考虑先随便找一个点作为根,然后再慢慢移动根,这样一步步走到最优的点

设 $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]幻想乡战略游戏的更多相关文章

  1. 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告

    P3345 [ZJOI2015]幻想乡战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做 ...

  2. P3345 [ZJOI2015]幻想乡战略游戏 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...

  3. 洛谷P3345 [ZJOI2015]幻想乡战略游戏 [动态点分治]

    传送门 调了两个小时,终于过了-- 凭啥人家代码80行我180行啊!!! 谁叫你大括号换行 谁叫你写缺省源 思路 显然,补给点所在的位置就是这棵树的带权重心. 考虑size已知时如何找重心:一开始设答 ...

  4. 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)

    洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...

  5. 2018.08.28 洛谷P3345 [ZJOI2015]幻想乡战略游戏(点分树)

    传送门 题目就是要求维护带权重心. 因此破题的关键点自然就是带权重心的性质. 这时发现直接找带权重心是O(n)的,考虑优化方案. 发现点分树的树高是logn级别的,并且对于以u为根的树,带权重心要么就 ...

  6. BZOJ 3924 / Luogu P3345 [ZJOI2015]幻想乡战略游戏 (动态点分治/点分树)

    题意 树的结构不变,每个点有点权,每一条边有边权,有修改点权的操作,设xxx为树中一点.求∑idist(x,i)∗a[i]\sum_idist(x,i)*a[i]i∑​dist(x,i)∗a[i]的最 ...

  7. AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345

    [ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...

  8. [ZJOI2015]幻想乡战略游戏——动态点分治

    [ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...

  9. BZOJ3924 ZJOI2015 幻想乡战略游戏 【动态点分治】

    BZOJ3924 ZJOI2015 幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂 ...

随机推荐

  1. iframe 模拟ajax文件上传and formdata ajax 文件上传

    对于文件上传 有好多种方式,一直想总结 文件上传的方法 今天就来写下 iframe  的文件上传的代码 本人语言表达能里有限,不多说了 直接上代码. 首先看 总体页面. 总共就三个文件. 实际上也就是 ...

  2. 268. Missing Number序列中遗失的数字

    [抄题]: Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is ...

  3. OpenNebula 深入分析

    -------------------OpenNebula 深入分析------------------- #容量清单 属性 描述 NAME 如果名字是空的,那么默认名字是:one-<VID&g ...

  4. c语言实践 1/1-1/2+1/3-1/4+...

    其实这个题目和上面那个是一样的 /* 1/1-1/2+1/3-1/4+...1/n; */ int n = 1; double sum = 0; double frac = 0; int i = 1; ...

  5. python 字符串,元组, 列表,字典之间的转换

    #-*-coding:utf-8-*- #1.字典 dict = {'name': 'Zara', 'age': 7, 'class': 'First'} #字典转为字符串,返回:<type ' ...

  6. MongoDB整理笔记のReplica Sets

    MongoDB支持在多个机器中通过异步复制达到故障转移和实现冗余.多机器中同一时刻只有一台机器是用于写操作,正因为如此,MongoDB提供了数据一致性的保障.而担当primary角色的机器,可以把读的 ...

  7. quartz 使用配置文件配置线程数

    quartz默认的线程数是10个,如果我们要修改这个线程数需要做一个配置文件,在配置文件内修改线程. 一共需要2个操作: 1.找到quartz的XML配置文件,设置加载配置文件(配置文件存放在weba ...

  8. Node简单服务器开发

    运用的知识:http,fs,get,post 接口定义:/user?act=reg$user=aaa&pass=bbb后台返回格式:{"ok":false,"ms ...

  9. k8s学习笔记(一)

    你将学到什么 如何部署k8s集群 网络拓扑 主机名 网络地址 角色 study 92.0.0.50(内网) 192.168.203.250/19(外网) Master fnode 92.0.0.16( ...

  10. 第十篇 requests模块

    1.安装requests 要安装requests,在终端中输入以下命令即可安装: pip3 install requests 2.发送请求 使用requests发送请求首先需要导入requests模块 ...