[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]的最 ...
随机推荐
- 利用Java反射根据类的名称获取属性信息和父类的属性信息
代码: import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java ...
- 路飞学城Python-Day21(practise)
编写程序, 如下有三点要求: 自定义用户信息数据结构, 写入文件, 然后读取出内容, 利用json模块进行数据的序列化和反序列化 e.g { "egon":{"passw ...
- linux C++ 编译错误 file not found 其实是原文件后缀的问题
gcc和clang会根据源文件的后缀.c或者.cpp判断原文件类型,采取不同的编译策略,所以我使用它们编译后缀是.c的C++原文件的时候会出现找不到include的文件的错误,使用正确的后缀名即可.同 ...
- 设置Django关闭Debug后的静态文件路由
Django在Debug模式关闭掉后请求静态文件时,返回404相应码,后台的请求url是"GET /static/css/404.css HTTP/1.1" 404 1217,找不 ...
- CGI与ISAPI的区别(转)
一 CGI原理及其性能 1) CGI概念CGI即通用网关接口(Common Gateway Interface),它是一段程序,运行在服务器上,提供同客户端HTML页面的交互,通俗的讲CGI就象是一座 ...
- linux日常指令、概念
指令 cal 查看日历date 查看日期bc 计算器ls 查看文件ls -l 查看具体信息(权限,时间等)ls -a 查看所有的文件包括隐藏文件ll 作用同上d* 开头的都是文件夹,- 开头的都是文件 ...
- Sublime 插件Pylinter could not automatically determined the path to lint.py
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/50618630 安装Sublime Te ...
- ssm框架下上传图片及其他信息
先引入这两个包: <dependency> <groupId>commons-fileupload</groupId> <artifactId>comm ...
- HDU 4259
虽然知道是置换,却很久没有思路.忽然想到,由初始状态A经过变换后回到A状态,应该是不停循环可重复的.于是,猜想数字的位置也是重复循环的.拿了个例子验证了一下,某然是这样.例如第二个10,3的例子有1- ...
- HDU 2841
明显,当(X,Y)=1时,是可以看见的. 这题,记得POJ 上也有类似的一题... 不过比较奇怪的是,我以为会超时,因为范围达到了100000,但竟然直接枚举没超时.... #include < ...