[BZOJ3924][ZJOI2015]幻想乡战略游戏-动态树分治
2017-10-03 23:42
330 查看
幻想乡战略游戏
Description
傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了。 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决。 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来。在游戏中,幽香可能在空地上增加或者减少一些军队。同时,幽香可以在一个空地上放置一个补给站。 如果补给站在点u上,并且空地v上有dv个单位的军队,那么幽香每天就要花费dv×dist(u,v)的金钱来补给这些军队。由于幽香需要补给所有的军队,因此幽香总共就要花费为Sigma(Dv*dist(u,v),其中1<=V<=N)的代价。其中dist(u,v)表示u个v在树上的距离(唯一路径的权和)。 因为游戏的规定,幽香只能选择一个空地作为补给站。在游戏的过程中,幽香可能会在某些空地上制造一些军队,也可能会减少某些空地上的军队,进行了这样的操作以后,出于经济上的考虑,幽香往往可以移动他的补给站从而省一些钱。但是由于这个游戏的地图是在太大了,幽香无法轻易的进行最优的安排,你能帮帮她吗? 你可以假定一开始所有空地上都没有军队。Input
第一行两个数n和Q分别表示树的点数和幽香操作的个数,其中点从1到n标号。接下来n-1行,每行三个正整数a,b,c,表示a和b之间有一条边权为c的边。
接下来Q行,每行两个数u,e,表示幽香在点u上放了e单位个军队
(如果e<0,就相当于是幽香在u上减少了|e|单位个军队,说白了就是du←du+e)。
数据保证任何时刻每个点上的军队数量都是非负的。
1<=c<=1000, 0<=|e|<=1000, n<=10^5, Q<=10^5
对于所有数据,这个树上所有点的度数都不超过20
N,Q>=1
Output
对于幽香的每个操作,输出操作完成以后,每天的最小花费,也即如果幽香选择最优的补给点进行补给时的花费。Sample Input
10 51 2 1
2 3 1
2 4 1
1 5 1
2 6 1
2 7 1
5 8 1
7 9 1
1 10 1
3 1
2 1
8 1
3 1
4 1
Sample Output
01
4
5
6
样例有误,输入边的地方有两行边权和点的编号中间没加空格……
话说一遍过还真是舒服啊
难道咱有写工业题的潜质?
(今早NOIP模拟题T1誓死不用STL写出280+行,STL党仅需120+行(虽然还是A了))
思路:
如果可以动态维护每个点的答案值,那么就可以很稳地做出此题。
可以发现,如果咱记录点u的子树点权和sumd[u],那么如果u到当前要计算值的点需要经过其父亲边向父亲走,那么这条父亲边对答案的贡献便是其权值*sumd[u]。
那么考虑维护sumd[u]来求答案。
考虑到出题人必须要足够坑的基本素质,每次如果暴力修改,复杂度会是是O(n)的,单次询问由于需要计算经过的点,复杂度也是O(n)的。
那这就会很尴尬地TLE了……
考虑使用动态点分治优化树的结构——建出树高仅为log的点分树。
所谓点分树,就是在点分治时把各个分治中心连在一起得到的一棵树~
那么可以发现之前的式子无法直接使用边权,而且还需要减去与父亲节点之间相冲突的子树部分。
那就维护一个dis,代表以u为根的子树中,所有节点到u的父亲所需的价值和,再维护一个fadis,代表以u为根的子树中,所有节点到u所需的价值和。
(名字很奇怪对吧只是咱写代码时写反了而已)
这两个值可以在修改操作时维护一下。
那么这就可以用加减法排除掉重复子树的影响了~~
修改直接暴力从被修改点开始往上一个个暴力跳父亲,反正点分树深度log~
至于查询,可以发现(显然是错的,显然可以随手卡掉)新的答案位置在原树上不会距离上一个答案位置太远。
那就在原树上暴力跳可好??反正单点价值查询只是log~~
(10s时限只用了4s证明效果还是不错的)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; const ll N=1e5+9; const ll K=22; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0' || '9'<ch){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar(); return x*f; } inline void chkmax(ll &a,ll b){if(a<b)a=b;} inline ll minn(ll a,ll b){if(a<b)return a;return b;} ll n,q,lans=1; ll d ; namespace tree { ll to[N<<1],nxt[N<<1],w[N<<1],beg ,tot=1; ll id ,dfn,st[N<<1][K],dep ,logs[N<<1]; ll fa ,sumd ,dis ,fadis ; bool ban[N<<1]; inline void add(int u,int v,int c) { to[++tot]=v; nxt[tot]=beg[u]; w[tot]=c; beg[u]=tot; } inline void dfs(ll u,ll fat=0) { st[++dfn][0]=dep[u]; id[u]=dfn; for(ll i=beg[u],v;i;i=nxt[i]) if((v=to[i])!=fat) { dep[v]=dep[u]+w[i]; dfs(v,u); st[++dfn][0]=dep[u]; } } inline void init() { for(ll i=2;i<=dfn;i++) logs[i]=logs[i>>1]+1; for(ll i=1;i<=logs[dfn];i++) for(ll j=1;j+(1<<i)-1<=dfn;j++) st[j][i]=minn(st[j][i-1],st[j+(1<<i-1)][i-1]); } inline ll dist(ll u,ll v) { ll ret=dep[u]+dep[v]; u=id[u],v=id[v]; if(u>v)swap(u,v); ll dis=logs[v-u+1]; return ret-2*minn(st[u][dis],st[v-(1<<dis)+1][dis]); } inline ll get_siz(ll u,ll fa=0) { ll siz=1; for(ll i=beg[u];i;i=nxt[i]) if(!ban[i] && to[i]!=fa) siz+=get_siz(to[i],u); return siz; } inline ll get_center(ll u,ll fa,ll totsiz,ll &root) { ll mxsiz=0,siz=1; for(ll i=beg[u],v,tmp;i;i=nxt[i]) if(!ban[i] && (v=to[i])!=fa) { siz+=(tmp=get_center(v,u,totsiz,root)); chkmax(mxsiz,tmp); } chkmax(mxsiz,totsiz-siz); if((mxsiz<<1)<=totsiz) root=u; return siz; } inline ll solve(ll u) { ll totsiz=get_siz(u),root; get_center(u,0,totsiz,root); sumd[root]=d[root]; for(ll i=beg[root],son;i;i=nxt[i]) if(!ban[i]) { ban[i]=ban[i^1]=1; son=solve(to[i]); fa[son]=root; sumd[root]+=sumd[son]; } return root; } inline void update(ll u,ll val) { sumd[u]+=val; for(ll i=u;fa[i];i=fa[i]) { ll diss=dist(fa[i],u); sumd[fa[i]]+=val; dis[i]+=val*diss; fadis[fa[i]]+=val*diss; } } inline ll calc(ll u) { ll ret=fadis[u]; for(ll i=u;fa[i];i=fa[i]) { ret+=(fadis[fa[i]]-dis[i]); ret+=dist(fa[i],u)*(sumd[fa[i]]-sumd[i]); } return ret; } inline ll query(ll u)//no fa anymore { ll ret=calc(u); for(ll i=beg[u],v;i;i=nxt[i]) if(calc(v=to[i])<ret) return query(v); lans=u; return ret; } } using namespace tree; int main() { if(fopen("tree.in","r")) { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); } n=read(); q=read(); for(ll i=1,u,v,c;i<n;i++) { u=read(); v=read(); c=read(); add(u,v,c); add(v,u,c); } dfs(1); init(); solve(1); for(ll i=1,u,e;i<=q;i++) { u=read(); e=read(); update(u,e); printf("%lld\n",query(lans)); } return 0; }
相关文章推荐
- bzoj 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ 3924 Zjoi2015 幻想乡战略游戏 动态树分治
- 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏 动态树分治
- BZOJ3924 : [Zjoi2015]幻想乡战略游戏
- BZOJ3924 : [Zjoi2015]幻想乡战略游戏
- [BZOJ3924][ZJOI2015]幻想乡战略游戏(动态点分治)
- 【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
- [点分树] BZOJ 3924 [Zjoi2015]幻想乡战略游戏
- 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏
- 【BZOJ 3924】【ZJOI 2015】幻想乡战略游戏
- BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)
- [BZOJ3924][Zjoi2015][点分树][暴力]幻想乡战略游戏
- [BZOJ3924][Zjoi2015]幻想乡战略游戏(动态点分治)
- [BZOJ]3924 [ZJOI2015] 幻想乡战略游戏 树链剖分
- bzoj 3924: [Zjoi2015]幻想乡战略游戏
- bzoj3924 [Zjoi2015]幻想乡战略游戏(动态点分治)