[ZJOI2015]幻想乡战略游戏(点分树)
题意自己看。。。
思路
没想到今(昨)天刷着刷着点分治的水题,就刷出来了一个点分树。。。
然后就疯狂地找题解,代码,最后终于把它给弄懂了。
点分树——动态点分治,对于此题来说,我们设u为当前的补给站位置,v是它的一个儿子。同时设dis(i,j)为树上i点到j点的距离。cnti为以i为根的子树中d(也就是军队数)的总量
我们把补给站从u转移到v(假设u是树的根),答案的变化为dis(u,v)*(cntu-cntv)-dis(u,v)*cntv=dis(u,v)*(cntu-2*cntv)
所以当2*cntv>cntu把补给站转移v会使答案变优,一直这样操作下去,直到不管如何转移都无法使答案变优,当前点就是答案。
我们对于每一次修改都维护一下然后默认当前点为补给站且为当前树的根,然后像刚才一样转移补给站,就有了这个题的大体思路。
但这样肯定会爆炸啊(每次只会转移一步,复杂度和深度有关)
所以我们就可以用到点分树了。
我们利用点分治的方法(找重心作为根节点,然后递归处理子树)重新构建一颗树,称为分治树。
举个例子,比如说样例
(左为原树右为分治树)
这样我们就得到一颗深度为log的树。
这样我们转移就不会因为深度太大而GG了。
但是,这样一来的话因为树的结构不一样了,补给站的转移就会很难。因为一个点在分治树的儿子在原树中不一定和它直接相连
(之后我们的补给站的转移都是在分治树上进行的)
但还是有办法解决的。我们记录这这些东西。dis(i,j)为i,j在原树的距离。cnt[i]为分治树中以i为根的子树中有多少个d,sumi为分治树中以i为根的子树中所有的点j的dis(i,j)*dj之和,sumch(i,j)记录i点第j个儿子的sum。
我们现在讨论从u转移到它分治树中的一个子节点v,v是原来这颗子树中的重心但在原树中并不一定和u之间相连,我们设原树中直接和u相连的点是w。
因为把补给站转到v的时候要把v作为整棵树的根,只要把v所在子树之外的所有信息扔到w中然后递归就可以了。那怎么维护w的信息呢?
我们记录在v处记录下w和w与u这条边的权值c,然后我们在cntw处加上cnt[u]-cnt[v],然后在sumw处加上sum[u]-sumch(i,v)+(cnt[u]-cnt[v])*c;
最后答案就取sum[当前点]就行了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define int long long
const int N=1e5+;
struct son{int v,rv,w;};
struct node{int u,c,w;};
struct pre{int to,w;};
vector<son>ch[N];
vector<node>stack;
vector<pre>f[N];
vector<int>sumch[N];
int num,head[N];
int g[N],root,size[N],all,vis[N];
int realroot,sum[N],cnt[N],n,m;
struct edge{
int to,nxt,w;
}e[N*];
void add_edge(int u,int v,int w){
num++;
e[num].nxt=head[u];
e[num].to=v;
e[num].w=w;
head[u]=num;
}
int read(){
int sum=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){sum=sum*+ch-'';ch=getchar();}
return sum*f;
}
void getroot(int u,int f){
g[u]=;size[u]=;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f||vis[v])continue;
getroot(v,u);
g[u]=max(g[u],size[v]);
size[u]+=size[v];
}
g[u]=max(g[u],all-size[u]);
if(g[u]<g[root])root=u;
}
void dfs(int u,int fa,int top,int w){
pre x;x.to=top;x.w=w;
f[u].push_back(x);
size[u]=;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v]||v==fa)continue;
dfs(v,u,top,w+e[i].w);
size[u]+=size[v];
}
}
void work(int u){
pre y;y.w=;y.to=u;
f[u].push_back(y);
vis[u]=;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v]==)continue;
dfs(v,,u,e[i].w);
root=,all=size[v];
getroot(v,);
son x;x.v=root;x.rv=v;x.w=e[i].w;
ch[u].push_back(x);
work(root);
}
}
void update(int u,int c,int w){
for(int i=;i<f[u].size();i++){
int v=f[u][i].to;
int L=f[u][i].w;
cnt[v]+=c;
sum[v]+=w+c*L;
if(i!=f[u].size()-)
for(int j=;j<ch[v].size();j++){
if(ch[v][j].v==f[u][i+].to)sumch[v][j]+=w+c*L;
}
}
}
int check(){
int now=realroot,mx;
stack.clear();
while(now){
mx=;
for(int i=;i<ch[now].size();i++)
if(cnt[ch[now][i].v]>cnt[ch[now][mx].v])mx=i;
if(ch[now].size()==||cnt[ch[now][mx].v]*<=cnt[now]){
int ans=sum[now];
for(int i=;i<stack.size();i++)
update(stack[i].u,stack[i].c,stack[i].w);
return ans;
}
int v=ch[now][mx].v;
node x;
x.u=ch[now][mx].rv;x.c=-(cnt[now]-cnt[v]);
x.w=-(sum[now]-sumch[now][mx]+(cnt[now]-cnt[v])*ch[now][mx].w);
stack.push_back(x);
update(x.u,-x.c,-x.w);
now=v;
}
}
signed main(){
n=read();m=read();
for(int i=;i<n;i++){
int u=read(),v=read(),w=read();
add_edge(u,v,w);add_edge(v,u,w);
}
g[]=n+;root=;all=n;
getroot(,);realroot=root;
work(root);
for(int i=;i<=n;i++)sumch[i]=vector<int>(ch[i].size(),);
while(m--){
int x=read(),y=read();
update(x,y,);
printf("%lld\n",check());
}
return ;
}
[ZJOI2015]幻想乡战略游戏(点分树)的更多相关文章
- bzoj3924 [Zjoi2015]幻想乡战略游戏 点分树,动态点分
[BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ...
- 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治
[BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ...
- 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告
P3345 [ZJOI2015]幻想乡战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做 ...
- BZOJ3924 ZJOI2015 幻想乡战略游戏 【动态点分治】
BZOJ3924 ZJOI2015 幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂 ...
- [ZJOI2015]幻想乡战略游戏——动态点分治
[ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...
- AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345
[ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...
- 2018.08.28 洛谷P3345 [ZJOI2015]幻想乡战略游戏(点分树)
传送门 题目就是要求维护带权重心. 因此破题的关键点自然就是带权重心的性质. 这时发现直接找带权重心是O(n)的,考虑优化方案. 发现点分树的树高是logn级别的,并且对于以u为根的树,带权重心要么就 ...
- 【洛谷3345_BZOJ3924】[ZJOI2015]幻想乡战略游戏(点分树)
大概有整整一个月没更博客了 -- 4 月为省选爆肝了一个月,最后压线进 B 队,也算给 NOIP2018 翻车到 316 分压线省一这个折磨了五个月的 debuff 画上了一个不算太差的句号.结果省选 ...
- BZOJ 3924 / Luogu P3345 [ZJOI2015]幻想乡战略游戏 (动态点分治/点分树)
题意 树的结构不变,每个点有点权,每一条边有边权,有修改点权的操作,设xxx为树中一点.求∑idist(x,i)∗a[i]\sum_idist(x,i)*a[i]i∑dist(x,i)∗a[i]的最 ...
随机推荐
- canvas 画图优化
http://www.cnblogs.com/rhcad/archive/2012/11/17/2774794.html
- ZBrush中自动保存在哪里
在使用 ZBrush®执行任何会话期间,您都可以设置将文件自动保存,并可以修改保存时间间隔,文件保存位置等设置.发生系统错误后要重新启动ZBrush时,可以从临时文件夹或指定的文件夹中恢复备份文件.如 ...
- python中return和print的区别(详细)
huskiesir最近在研究python哈,今天纠结一个问题,那就是return和print的区别,都是可以输出结果的,到底有啥区别呀?二话不多说,看下面的例子. #代码1: def break_wo ...
- NetApp 存储的常用概念普及
NetApp 存储的常用概念和命令1. Volume 和qtree卷(volume)是filer 上的一个基本空间单位,它可以是基于aggr划出的灵活卷(flexvol),也可以是直接由物理盘组成的传 ...
- jsonp实现原理
jquery 封装在 ajax方法 里面的jsonp jsonp跨域的原理 1:使用script 标签发送请求,这个标签支持跨域访问 2:在script 标签里面给服务器端传递 ...
- Spring配置文件中指定init-method属性的作用
bean 配置文件属性 init-method 用于在bean初始化时指定执行方法,用来替代继承 InitializingBean接口.相关链接:https://www.cnblogs.com/Joe ...
- [terry笔记]python FTP
如下是作业,用python做一个ftp,主要利用socket. server端在linux下运行,在client端可以执行shell命令(静态的) 在client端输入get xxx,即可下载. 在c ...
- UVALive 3231 Fair Share
Fair Share Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Origina ...
- 今天修了一个bug,关于debug日志的问题
是别人的代码,很诡异. 就是开了debug日志,没问题. 关了debug日志,就出问题. 开始我以为是debug日志拖慢了速度,所以有一些竞态环境的影响. 后来发现是在debug日志里面有一些side ...
- [Angular + Unit Testing] Mock HTTP Requests made with Angular’s HttpClient in Unit Tests
In a proper unit test we want to isolate external dependencies as much as possible to guarantee a re ...