题目链接:https://www.luogu.org/problemnew/show/P3345(bzoj权限题)

题意概述:动态维护树的上所有点到这棵树的带权重心的距离和。N,Q<=100000.

分析:

  首先考虑一个性质,对于任意一个点i来说,如果存在一个儿子j使得sz[j]*2>tot,那么i一定不是树的重心,并且重心应该在j的子树中,否则重心就可以是i。(这里必须是事先积累的知识,证明简单,略)

  于是就可以考虑一个暴力辣!每次从根出发按照上面的条件进行查找,一旦发现一个点没有儿子满足上面的性质,那么这个点就应该是一个重心。

  但是这样一次次走很慢。注意到我们找的是深度最大的j满足sz[j]*2>tot(满足条件的j一定在一条链上面),这里有很多的做法,但是考虑到我们计算答案的时候可能用到树剖,所以我们选择在DFS序上面操作,维护区间的sz最大值,直接在线段树上来二分查找,一次查找当前重心的复杂度是O(logn)。

  关于答案的计算,我们发现对于点i为重心的时候,其答案分成两部分,一个是i的子树,一个是i的祖先。我们单独计算每个祖先不包含i的其余子树的贡献,全部加起来就是这次的答案。

  通过计算,一次的答案可以表示为:

    sum[1]+d[i]*(tot-sz[i])-sum{ f(j) | j为i到1路径上的节(包括i)) }

    f(i)=sz[i]*(d[i]-d[fa[i]])+(sz[fa[i]]-sz[i])*d[fa[i]]

    sum[i]表示i的子树中的点到i的带权距离和,sz[i]表示i的子树中所有点的权值和,d[i]表示i到1的路径长度,tot表示所有点的权值和。

  维护:树剖,维护所有的sz和f以及sz的最大值,重链顶端的点不要去维护,每一次跳到的时候单独计算其f(因为没有办法同时维护一个点所有的儿子的f)。每次修改一个点的权值之后,其到1路径上所有点的sz都会改变,我们发现这些点的f值会发生变化,同时在更新中我们到达的所有的点的重儿子的f也会发生变化,记得更新一下。

  时间复杂度O(N+Q*logN^2)

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
typedef long long LL; int N,Q;
struct segment_tree{
static const int maxn=;
struct edge{ int to,next,w; }E[maxn<<];
int first[maxn],np,n,dist[maxn],_sz[maxn],fa[maxn],son[maxn],top[maxn];
int dfs_clock,l[maxn],a[maxn],sz[maxn];
int rt,np2,lc[maxn<<],rc[maxn<<],mx[maxn<<],flag[maxn<<],tot;
LL g[maxn<<],sum;
segment_tree(){ sum=np=np2=rt=; }
void add_edge(int u,int v,int w){
E[++np]=(edge){v,first[u],w};
first[u]=np;
}
void DFS1(int i,int f,int l){
fa[i]=f,dist[i]=l;
_sz[i]=,sz[i]=;
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(j==f) continue;
DFS1(j,i,l+E[p].w);
_sz[i]+=_sz[j];
if(_sz[j]>_sz[son[i]]) son[i]=j;
}
}
void DFS2(int i,int f,int tp){
top[i]=tp,l[i]=++dfs_clock;
a[dfs_clock]=i;
if(son[i]) DFS2(son[i],i,tp);
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(j==f||j==son[i]) continue;
DFS2(j,i,j);
}
}
void pushup(int now){
mx[now]=max(mx[lc[now]],mx[rc[now]]);
g[now]=g[lc[now]]+g[rc[now]];
}
void pushdown(int now,int L,int R){
if(!flag[now]) return;
int m=L+R>>;
if(top[a[L]]==a[L]) g[lc[now]]+=1ll*flag[now]*(dist[a[m]]-dist[a[L]]);
else g[lc[now]]+=1ll*flag[now]*(dist[a[m]]-dist[fa[a[L]]]);
if(top[a[m+]]==a[m+]) g[rc[now]]+=1ll*flag[now]*(dist[a[R]]-dist[a[m+]]);
else g[rc[now]]+=1ll*flag[now]*(dist[a[R]]-dist[a[m]]);
mx[lc[now]]+=flag[now],mx[rc[now]]+=flag[now];
flag[lc[now]]+=flag[now],flag[rc[now]]+=flag[now];
flag[now]=;
}
void build(int &now,int L,int R){
now=++np2,lc[now]=rc[now]=;
g[now]=mx[now]=flag[now]=;
if(L==R) return;
int m=L+R>>;
build(lc[now],L,m); build(rc[now],m+,R);
}
int query_p(int now,int L,int R){
if(L==R) return a[L];
pushdown(now,L,R);
int m=L+R>>;
if(mx[rc[now]]*>tot) return query_p(rc[now],m+,R);
return query_p(lc[now],L,m);
}
void query(int now,int L,int R,int pos){
if(L==R){
sz[a[L]]+=flag[now],flag[now]=;
return;
}
pushdown(now,L,R);
int m=L+R>>;
if(pos<=m) query(lc[now],L,m,pos);
else query(rc[now],m+,R,pos);
}
LL query_g(int now,int L,int R,int A,int B){
if(A<=L&&R<=B) return g[now];
pushdown(now,L,R);
int m=L+R>>;
if(B<=m) return query_g(lc[now],L,m,A,B);
if(A>m) return query_g(rc[now],m+,R,A,B);
return query_g(lc[now],L,m,A,B)+query_g(rc[now],m+,R,A,B);
}
void update1(int now,int L,int R,int A,int B,int delt){
if(A<=L&&R<=B){
mx[now]+=delt,flag[now]+=delt;
if(top[a[L]]==a[L]) g[now]+=1ll*delt*(dist[a[R]]-dist[a[L]]);
else g[now]+=1ll*delt*(dist[a[R]]-dist[fa[a[L]]]);
return;
}
pushdown(now,L,R);
int m=L+R>>;
if(B<=m) update1(lc[now],L,m,A,B,delt);
else if(A>m) update1(rc[now],m+,R,A,B,delt);
else update1(lc[now],L,m,A,B,delt),update1(rc[now],m+,R,A,B,delt);
pushup(now);
}
void update2(int now,int L,int R,int pos,int delt){
if(L==R){
sz[a[L]]+=flag[now],flag[now]=;
if(top[a[L]]!=a[L]) g[now]+=1ll*delt*dist[fa[a[L]]];
return;
}
pushdown(now,L,R);
int m=L+R>>;
if(pos<=m) update2(lc[now],L,m,pos,delt);
else update2(rc[now],m+,R,pos,delt);
pushup(now);
}
void update(int p,int delt){
tot+=delt,sum+=1ll*delt*dist[p];
while(p){
update1(rt,,n,l[top[p]],l[p],delt);
if(son[p]) update2(rt,,n,l[son[p]],delt);
p=fa[top[p]];
}
}
LL ans(){
int p=query_p(rt,,n);
query(rt,,n,l[p]);
LL re=sum+1ll*dist[p]*(tot-sz[p]);
while(p){
re-=query_g(rt,,n,l[top[p]],l[p]);
p=top[p];
query(rt,,n,l[p]); query(rt,,n,l[fa[p]]);
re-=1ll*sz[p]*(dist[p]-dist[fa[p]])+1ll*(sz[fa[p]]-sz[p])*dist[fa[p]];
p=fa[p];
}
return re;
}
}st; bool nega;
void _scanf(int &x)
{
x=,nega=;
char ch=getchar();
while((ch<''||ch>'')&&ch!='-') ch=getchar();
if(ch=='-') nega=,ch=getchar();
while(ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
if(nega) x=-x;
}
int out_cnt,out[];
void _printf(LL x)
{
out[++out_cnt]=x%,x/=;
while(x) out[++out_cnt]=x%,x/=;
while(out_cnt) putchar(''+out[out_cnt--]);
putchar('\n');
}
void data_in()
{
_scanf(N);_scanf(Q); st.n=N;
int x,y,z;
for(int i=;i<N;i++){
_scanf(x);_scanf(y);_scanf(z);
st.add_edge(x,y,z); st.add_edge(y,x,z);
}
}
void work()
{
int u,e;
st.DFS1(,,);
st.DFS2(,,);
st.build(st.rt,,st.n);
for(int i=;i<=Q;i++){
_scanf(u);_scanf(e);
st.update(u,e);
_printf(st.ans());
}
}
int main()
{
data_in();
work();
return ;
}

BZOJ 3924 ZJOI2015 幻想乡战略游戏 树链剖分的更多相关文章

  1. bzoj 3924: [Zjoi2015]幻想乡战略游戏

    Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ...

  2. bzoj 3924 [Zjoi2015]幻想乡战略游戏——动态点分治(暴力移动找重心)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3924 度数只有20,所以从一个点暴力枚举其出边,就能知道往哪个方向走. 知道方向之后直接走到 ...

  3. BZOJ 3924: [Zjoi2015]幻想乡战略游戏(动态点分治)

    这种动态点分治嘛,GDKOI时听打到了,也有同学讲到了,所以印象比较深刻也就想出来了,然后就在实现方面卡了好久= = 不得不说CLJ说得真的太简单了,实现方面根本没提. 首先我们可以先用树分治构建出这 ...

  4. bzoj3924 [Zjoi2015]幻想乡战略游戏 点分树,动态点分

    [BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ...

  5. 【BZOJ3924】[Zjoi2015]幻想乡战略游戏 动态树分治

    [BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ...

  6. 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告

    P3345 [ZJOI2015]幻想乡战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做 ...

  7. [ZJOI2015]幻想乡战略游戏——动态点分治

    [ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...

  8. BZOJ3924 ZJOI2015 幻想乡战略游戏 【动态点分治】

    BZOJ3924 ZJOI2015 幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂 ...

  9. AC日记——[ZJOI2015]幻想乡战略游戏 洛谷 P3345

    [ZJOI2015]幻想乡战略游戏 思路: 树剖暴力转移: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1 ...

随机推荐

  1. swift实现一个对象池

    1.创建一个对象池 对象池:对象池一般用来管理一组可重用的对象, 这些对象的集合叫做对象池. 组件可以从对象池中借用对象, 完成一些任务之后将它归还给对象池. 返回的对象用于满足调用组件的后续请求, ...

  2. Mysql 之 MERGE 存储引擎

    MERGE 存储引擎把一组 MyISAM 数据表当做一个逻辑单元来对待,让我们可以同时对他们进行查询.构成一个 MERGE 数据表结构的各成员 MyISAM 数据表必须具有完全一样的表结构.每一个成员 ...

  3. 在vue中如何实现购物车checkbox的三级联动

    最近用vue写一个电商项目,自然就少不了要写一个购物车的相关页面,功能完整的购物车的checkbox应该是三级联动的,1级checkbox是选中购物车中所有的商品,2级checkbox是选中某个店铺下 ...

  4. QWebView 与Js 交互

    我本愚钝,在网上搜了一下没找到可以运行的栗子,遂在这记录一下吧. 环境:win10 64位系统  qt 4.8.7 (mingw32) qtcreator(4.5.0) 1. 建立一个 Widgets ...

  5. Docker入门系列02

    上篇用一个简单的示例,简单的介绍了 Dockerfile 的配置及其相关的命令.这一篇会在上篇的示例程序里,继续添加新代码及如何将单元测试也放入 Image 建立过程内. 首先,我们需要建一个新的类库 ...

  6. Fedora 下面安装FTP服务

    1. yum install vsftpd 2. systemctl disable vsftpd.service 3. systemctl stop vsftpd.service 4. system ...

  7. xshell5连接虚拟机的小问题处理

    1.首先确保虚拟机是桥接状态,然后在虚拟机下用ifconfig查看ip地址(当然是默认你虚拟机下是linux) 2.确保虚拟机安装了ssh...安装openssh-server: 对应的sudo ap ...

  8. Java设计模式(14)——行为模式之不变模式(Immutable)

    一.概述 概念 分类:弱不变模式(子类可变)和强不变模式(子类也是不可变) 应用场景 java.lang.String是一个经典的强不变类 二.分析 与享元模式的关系

  9. tutorials

    https://github.com/HadrienG/tutorials https://github.com/galaxyproject/training-material/blob/master ...

  10. vim程序员加强功能

    1.折叠      1.1折叠的方式有六种           manual:以标准的vim结构定义折叠跨越的范围,类似移动命令           indent:折叠与折叠的层次,对应于文本的缩排与 ...