[ZJOI2015]幻想乡战略游戏

题解

由于所有边的边权是正整数,所以可以发现任何时刻每个点的答案是从最优的点往周围递增的。如果有平台,那么一定是在最优点的连通块那儿。

我们先考虑如何快速求每个点的答案。把式子拆开来:
f u = ∑ v = 1 n ( d v ∗ d i s u , v ) = ∑ v = 1 n ( d v ∗ ( d e p u + d e p v − 2 ∗ d e p l c a ( u , v ) ) ) = d e p u ∗ ( ∑ v = 1 n d v ) + ∑ v = 1 n ( d v ∗ d e p v ) − ∑ v = 1 n ( d v ∗ 2 ∗ d e p l c a ( u , v ) ) f_u=\sum_{v=1}^n(d_v*dis_{u,v})\\ =\sum_{v=1}^n(d_v*(dep_u+dep_v-2*dep_{lca(u,v)}))\\ =dep_u*(\sum_{v=1}^nd_v)+\sum_{v=1}^n(d_v*dep_v)-\sum_{v=1}^n(d_v*2*dep_{lca(u,v)}) fu​=v=1∑n​(dv​∗disu,v​)=v=1∑n​(dv​∗(depu​+depv​−2∗deplca(u,v)​))=depu​∗(v=1∑n​dv​)+v=1∑n​(dv​∗depv​)−v=1∑n​(dv​∗2∗deplca(u,v)​)可以发现前两部分都是可以 O ( 1 ) O(1) O(1) 求的,第三部分我们可以用经典思路,把每个点的点权设为它的父亲边的长度,然后用树链剖分,每次修改把 x x x 到根的一条链的值全部减去2*点权,然后查询时只用求出到根的链上的值的和。

查询答案的问题解决了,剩下就可以直接用树剖在树上找最优点了。我们从任意一个点开始,它所在的重链的答案一定是单峰的,并且非峰顶的部分无平台,所以我们可以每条重链用平衡树维护之前的答案,然后在平衡树上二分找到峰顶。接下来全树最优点如果不是这个峰顶的话,必定要从这个峰顶走出这条重链去找,我们可以直接枚举与它相邻的点,那么此时最多有一个点的答案更优,走那个方向递归下去即可。

查询答案可以用全局平衡二叉树做到 O ( log ⁡ n ) O(\log n) O(logn)。这个做法毛估一下大概是 O ( n log ⁡ 3 n ) O(n\log^3n) O(nlog3n) 的,但是却跑得出奇地快(直接进入 O ( n log ⁡ n ) ∼ O ( n log ⁡ 2 n ) O(n\log n)\sim O(n\log^2 n) O(nlogn)∼O(nlog2n) 梯队),大概是因为其中的两个 log ⁡ \log log 都跑不满的缘故。

代码

#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define uns unsigned
#define IF (it->first)
#define IS (it->second)
#define END putchar('\n')
using namespace std;
const int MAXN=100005;
const ll INF=1e18;
inline ll read(){ll x=0;bool f=1;char s=getchar();while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();return f?x:-x;
}
int ptf[50],lpt;
inline void print(ll x,char c='\n'){if(x<0)putchar('-'),x=-x;ptf[lpt=1]=x%10;while(x>9)x/=10,ptf[++lpt]=x%10;while(lpt)putchar(ptf[lpt--]^48);if(c>0)putchar(c);
}
inline ll lowbit(ll x){return x&-x;}struct edge{int v,to;ll w;edge(){}edge(int V,int T,ll W){v=V,to=T,w=W;}
}e[MAXN<<1];
int EN,G[MAXN];
inline void addedge(int u,int v,ll w){e[++EN]=edge(v,G[u],w),G[u]=EN;e[++EN]=edge(u,G[v],w),G[v]=EN;
}
int n,m,siz[MAXN],fa[MAXN],hs[MAXN];
ll dep[MAXN],d[MAXN],sd,sdv;
int hd[MAXN],id[MAXN],IN,tl[MAXN],tp[MAXN],rt[MAXN];
struct itn{int ls,rs;ll a,s,g,f,lz;itn(){}itn(ll A){a=s=A,g=f=lz=0,ls=rs=0;}
}t[MAXN];
inline void cover(int x,ll z){if(!x)return;t[x].f+=t[x].s*z,t[x].g+=t[x].a*z,t[x].lz+=z;
}
inline void pushd(int x){if(t[x].lz)cover(t[x].ls,t[x].lz),cover(t[x].rs,t[x].lz),t[x].lz=0;
}
inline void update(int x){t[x].s=t[x].a+t[t[x].ls].s+t[t[x].rs].s;t[x].f=t[x].g+t[t[x].ls].f+t[t[x].rs].f;
}
inline void add(int x,int l,int r,int a,int b,ll d){if(!x||l>r)return;if(l>=a&&r<=b){cover(x,d);return;}pushd(x);if(x>=a&&x<=b)t[x].g+=t[x].a*d;if(a<x)add(t[x].ls,l,x-1,a,b,d);if(b>x)add(t[x].rs,x+1,r,a,b,d);update(x);
}
inline ll query(int x,int l,int r,int a,int b){if(!x||l>r)return 0;if(l>=a&&r<=b)return t[x].f;ll res=(x>=a&&x<=b?t[x].g:0);pushd(x);if(a<x)res+=query(t[x].ls,l,x-1,a,b);if(b>x)res+=query(t[x].rs,x+1,r,a,b);return res;
}inline int build(int l,int r){if(l>r)return 0;int p=0,s=0,x=l;for(int i=l;i<=r;i++)s+=siz[id[i]]-siz[hs[id[i]]];for(;x<r;x++){p+=siz[id[x]]-siz[hs[id[x]]];if((p<<1)>s)break;}t[x]=itn(dep[id[x]]-dep[fa[id[x]]]);t[x].ls=build(l,x-1),t[x].rs=build(x+1,r);return update(x),x;
}
inline void dfs1(int x){siz[x]=1,hs[x]=0;for(int i=G[x];i;i=e[i].to){int v=e[i].v;if(v==fa[x])continue;fa[v]=x,dep[v]=dep[x]+e[i].w;dfs1(v),siz[x]+=siz[v];if(siz[v]>siz[hs[x]])hs[x]=v;}
}
inline void dfs2(int x){hd[x]=++IN,id[IN]=x,tp[x]=(x==hs[fa[x]]?tp[fa[x]]:x),tl[tp[x]]=IN;if(hs[x])dfs2(hs[x]);for(int i=G[x];i;i=e[i].to){int v=e[i].v;if(v==fa[x]||v==hs[x])continue;dfs2(v);}if(x==tp[x])rt[x]=build(hd[x],tl[x]);
}
inline void addl(int x,ll z){while(x)add(rt[tp[x]],hd[tp[x]],tl[tp[x]],hd[tp[x]],hd[x],z),x=fa[tp[x]];
}
inline ll schl(int x){ll res=0;while(x)res+=query(rt[tp[x]],hd[tp[x]],tl[tp[x]],hd[tp[x]],hd[x]),x=fa[tp[x]];return res;
}
inline ll getv(int x){return dep[x]*sd+sdv+schl(x);}
#define pli pair<ll,int>
#define fi first
#define se second
inline pli schmn(int x,int l,int r,ll pr){if(!x||l>r)return pli(INF,0);ll pv=INF;pushd(x);pli res=pli(pr+t[t[x].ls].f+t[x].g+dep[id[x]]*sd+sdv,id[x]);if(fa[id[x]])pv=pr+t[t[x].ls].f+dep[fa[id[x]]]*sd+sdv;if(pv<=res.fi)res=min(res,schmn(t[x].ls,l,x-1,pr));else res=min(res,schmn(t[x].rs,x+1,r,pr+t[t[x].ls].f+t[x].g));return res;
}
inline pli findp(int x){pli as=schmn(rt[tp[x]],hd[tp[x]],tl[tp[x]],schl(fa[tp[x]]));x=as.se;for(int i=G[x];i;i=e[i].to){int v=e[i].v;if(tp[v]==tp[x])continue;ll val=getv(v);if(val<as.fi)as=pli(val,v);}if(as.se^x)return findp(as.se);else return as;
}
signed main()
{n=read(),m=read();for(int i=1,u,v;i<n;i++)u=read(),v=read(),addedge(u,v,read());dfs1(1),dfs2(1);for(int i=1;i<=m;i++){int x=read(),e=read();sd+=e,sdv+=e*dep[x],addl(x,-(e<<1));print(findp(1).fi);}return 0;
}

[ZJOI2015] 幻想乡战略游戏——树链剖分相关推荐

  1. 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治

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

  2. P3345 [ZJOI2015]幻想乡战略游戏

    P3345 [ZJOI2015]幻想乡战略游戏 带修改带权重心 这是经典的树上寻找关键点的题目,我们使用点分治处理这个问题,因为点分治的特性,就相当于在树上二分了.但是这与倍增不同,倍增只是在链上二分 ...

  3. [ZJOI2015] 幻想乡战略游戏(树链剖分 + 线段树二分 + 带权重心)

    problem luogu-P3345 solution 这是一个带权重心的题,考察动态点分治.点分治?呵,不可能的,这辈子都不可能写点分治 我们重新考虑重心的性质:以这个点为根时,所有子树的大小不会 ...

  4. BZOJ3924 : [Zjoi2015]幻想乡战略游戏

    对于一个点,要求出它到所有点的带权距离和,只需记录下树分治的结构然后查询即可. 修改$O(\log n)$,查询$O(\log n)$. 到所有点带权距离和最小的点显然是这棵树的带权重心. 以1号点为 ...

  5. LG P3345 [ZJOI2015]幻想乡战略游戏(树的带权重心 + 树链剖分+ 动态点分治)

    题目 首先这个题看起来这个最小值不好在动态点分治时维护. (居然)可以转化. 最小值于树的带权重心处取到. 带权带的是点权. 树的带权重心是子树权∗2>=总树权子树权*2>=总树权子树权∗ ...

  6. 【洛谷3345_BZOJ3924】[ZJOI2015]幻想乡战略游戏(点分树)

    大概有整整一个月没更博客了 -- 4 月为省选爆肝了一个月,最后压线进 B 队,也算给 NOIP2018 翻车到 316 分压线省一这个折磨了五个月的 debuff 画上了一个不算太差的句号.结果省选 ...

  7. 【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治

    题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打 ...

  8. Bzoj3924 [Zjoi2015]幻想乡战略游戏

    Time Limit: 100 Sec  Memory Limit: 256 MB Submit: 817  Solved: 376 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏 ...

  9. luogu_P3345[zjoi2015]幻想乡战略游戏

    传送门 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看 ...

最新文章

  1. 1. 批量梯度下降法BGD 2. 随机梯度下降法SGD 3. 小批量梯度下降法MBGD
  2. 20145303 《信息安全系统设计基础》第3周学习总结
  3. 12 月机器学习新书:《可解释机器学习方法的局限》,免费下载!
  4. android怎么ota升级,Android OTA升级过程
  5. winfrom 从网页中通过源代码截取文章
  6. 【算法】剑指 Offer 46. 把数字翻译成字符串
  7. vuex 源码分析_Vuex源码解析(一):Module初始化
  8. ios keychain 不被清理_限免 | 可爱天气 清理君等等
  9. [置顶]       webservice系列1---基于web工程上写一个基本数据类型的webservice
  10. Python语音转文字、音频切割、语音识别
  11. 前端常用PS技巧总结之更换图片背景颜色
  12. 机器视觉打光方式相关问题汇总
  13. turlebot3 ROS相关求助
  14. 笔记本上的 Ctrl 键突然无法使用
  15. MediaPlayer基础
  16. YOLO V6系列(一) -- 跑通YOLO V6算法
  17. 中国石油大学《大学英语(三)统考》第八套模拟题
  18. 人与自然,《棕熊之王-下》
  19. java 串口 dtr rts_串口(RS232 RS485等)通讯中RTS/CTS,DTR/DSR的含义详解
  20. 14款web前端常用的富文本编辑器插件

热门文章

  1. 手机功能测试抓log方式(四种)
  2. 倡导低碳低成本出行,神州租车用实力说话
  3. C:\WINDOWS\system32\Macromed\Flash\Flash32_11_5_502_110.ocx
  4. Java打印折纸游戏
  5. 作业Android自我介绍
  6. 集装箱编号校验码规则及java程序的实现
  7. 一个事物两个方面的对比举例_象征和体现这两个词的区别  最好举例子说明,谢谢啦...
  8. 性格特点有哪些_各地区域文化不同,各省人的性格特点也千差万别之内蒙、四川...
  9. 魔百盒CDN00001_移动魔百盒设置最佳DNS方法
  10. 51单片机c语言16进制数转换10进制数,51单片机C语言里 怎样将16进制 直接化成 10进制...