bzoj 3924: [Zjoi2015]幻想乡战略游戏
2018-01-12 19:14
316 查看
Description
傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。
在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dvdist(u,v)的金钱来补给这些军队。
由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dvdist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的距离(唯一路径的权和)。
因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。
但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。
Solution
正解:动态点分基于本题性质:度数不超过20,否则不能这么做
问题是要求一个带权重心,我们可以移动重心找到最小的一个,关键在于计算贡献是 \(O(n)\) 的.
建立重心树,我们可以\(logn\)的算出建立在当前点的代价
设 \(dis[x]\) 表示x所在的块到x的距离\(dis*dv\)之和,\(disf[x]\)表示x所在的块到x的重心树上的父亲距离\(L*dv\)的距离之和,\(w[x]\) 为x块内的\(dv\)之和
那么遍历父亲就可以算出代价了,考虑两个块贡献合并:u为计算的点,设x为儿子,v为父亲,合并的贡献为:\(dis[v]+(val[v]-val[x])*L(v,u)-disf[x]\)
意思是不含\(x\)的块到\(v\)的点的距离之和,加上不含\(x\)所在块的部分到 \(u\) 的距离
重心的移动就是判断某个儿子是否是最优的,如果是,就进入这一个块中.
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=100005; int head ,nxt[N<<2],to[N<<2],num=0,c[N<<2],n,m,Head ; inline void link(int x,int y,int z){ nxt[++num]=head[x];to[num]=y;c[num]=z;head[x]=num;} namespace tr{ int dep ,sz ,son ,fa ,top ,dis ; inline void dfs1(int x){ sz[x]=1; for(int i=head[x];i;i=nxt[i]){ int u=to[i];if(dep[u])continue; dep[u]=dep[x]+1;dis[u]=dis[x]+c[i];fa[u]=x;dfs1(u); sz[x]+=sz[u];if(sz[u]>sz[son[x]])son[x]=u; } } inline void dfs2(int x,int tp){ top[x]=tp; if(son[x])dfs2(son[x],tp); for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa[x] && to[i]!=son[x])dfs2(to[i],to[i]); } inline int lca(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); x=fa[top[x]]; }return dep[x]<dep[y]?x:y; } inline int getdis(int x,int y){return dis[x]+dis[y]-(dis[lca(x,y)]<<1);} void main(){dep[1]=1;dfs1(1);dfs2(1,1);} } int rt=0,sz ,son ={N},sum,S,fa ;bool vis ; inline void link2(int x,int y,int v){ nxt[++num]=Head[x];to[num]=y;Head[x]=num;c[num]=v;} inline void getroot(int x,int last){ sz[x]=1;son[x]=0; for(int i=head[x];i;i=nxt[i]){ int u=to[i]; if(u==last || vis[u])continue; getroot(u,x);sz[x]+=sz[u]; son[x]=max(son[x],sz[u]); } son[x]=max(son[x],sum-sz[x]); if(son[x]<son[rt])rt=x; } inline void solve(int x){ vis[x]=1; for(int i=head[x];i;i=nxt[i]){ int u=to[i];if(vis[u])continue; rt=0;sum=sz[u];getroot(u,x);link2(x,rt,to[i]);fa[rt]=x; solve(rt); } } ll val ,dis ,disf ; inline void Modify(int x,int y){ for(int v=x;v;v=fa[v]){ val[v]+=y; dis[v]+=1ll*y*tr::getdis(x,v); if(fa[v])disf[v]+=1ll*y*tr::getdis(x,fa[v]); } } inline ll ask(int x){ ll ret=dis[x];int v=x; while(fa[v]){ ret+=dis[fa[v]]+(val[fa[v]]-val[v])*tr::getdis(fa[v],x)-disf[v]; v=fa[v]; } return ret; } inline ll qry(int x){ ll ret=ask(x); for(int i=Head[x];i;i=nxt[i]) if(ask(c[i])<ret)return qry(to[i]); return ret; } void work() { int x,y,z; scanf("%d%d",&n,&m); for(int i=1;i<n;i++){ scanf("%d%d%d",&x,&y,&z); link(x,y,z);link(y,x,z); } tr::main(); sum=n;rt=0;getroot(1,1);solve(S=rt); while(m--){ scanf("%d%d",&x,&y); Modify(x,y); printf("%lld\n",qry(S)); } } int main() { freopen("pp.in","r",stdin); freopen("pp.out","w",stdout); work(); return 0; }
相关文章推荐
- [BZOJ3924][ZJOI2015]幻想乡战略游戏(动态点分治)
- BZOJ3924 : [Zjoi2015]幻想乡战略游戏
- BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治
- 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ3924 : [Zjoi2015]幻想乡战略游戏
- [点分树] BZOJ 3924 [Zjoi2015]幻想乡战略游戏
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- 【BZOJ 3924】【ZJOI 2015】幻想乡战略游戏
- [BZOJ3924][ZJOI2015]幻想乡战略游戏-动态树分治
- [BZOJ3924][Zjoi2015][点分树][暴力]幻想乡战略游戏
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏
- bzoj 3924: [Zjoi2015]幻想乡战略游戏 (树链剖分)
- bzoj 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- bzoj 3924: [Zjoi2015]幻想乡战略游戏
- 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏
- 【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
- [BZOJ3924][Zjoi2015]幻想乡战略游戏(动态点分治)
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏
- bzoj3924 [Zjoi2015]幻想乡战略游戏(动态点分治)