[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+jxls利用excel模版进行导出
大多时候会出现需要导出excel的功能,利用poi可以实现简单的导出,可以说poi的功能非常强大可以做到细节的定制化操作,但相对于在office操作excel,利用poi完全生成excel会显得非常复 ...
- Day 07 -02 拷贝 浅拷贝 深拷贝
必考 存一个值还是多个值 一个值:整型/浮点型/字符串 多个值:列表/元祖/字典/集合 有序or 无序 有序:字符串/列表/元祖 无序:字典/集合 可变or 不可变 可变:列表/字典/集合 不可变:整 ...
- Android 开发者必知的开发资源
英文原文:Bongzimo 翻译: ImportNew-黄小非 译文链接:http://www.importnew.com/3988.html Android 开发者必知的开发资源 随着Androi ...
- BZOJ 2820 luogu 2257 yy的gcd (莫比乌斯反演)
题目大意:求$gcd(i,j)==k,i\in[1,n],j\in[1,m] ,k\in prime,n,m<=10^{7}$的有序数对个数,不超过10^{4}次询问 莫比乌斯反演入门题 为方便 ...
- 让前端攻城师独立于后端进行开发: Mock.js
一.Mock.js是什么? 目前的大部分公司的项目都是采用的前后端分离, 后端接口的开发和前端人员是同时进行的. 那么这个时候就会存在一个问题, 在页面需要使用大量数据进行渲染生成前, 后端开发人员的 ...
- 洛谷 P1313 计算系数 (二项式定理)
这道题正好复习了二项式定理 所以答案就是a^n * b^m * c(n, k) 然后注意一些细节 我一开始写组合数只写一行的组合数 即c[0] = 1; c[i] = c[i-1] * (n - i ...
- HDU 2643
(第二类斯特林数*N的阶乘 )的和. #include <iostream> #include <cstdio> #include <algorithm> #def ...
- 阿里云server部署架构
近期要上马一个项目,客户要求所有部署到阿里云的server,做了一个阿里云的部署方案. 上图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc21hbGx ...
- 题目1437:To Fill or Not to Fill(贪心算法)
题目描写叙述: With highways available, driving a car from Hangzhou to any other city is easy. But since th ...
- Android 的Recovery机制
Android 的Recovery机制 文件夹 1. 系统的启动模式 1 1.1 Android系统的启动模式 1 1.2 系统的启动模式 2 2. Recovery模式中的三个部分 3 3. Rec ...