题意

给一棵固定形态的树,边有边权,每次修改一条边权,在线求出修改后树的直径。


思考

写出树的全dfs序。生成方式为:每当一个点进栈或入栈时,记录它的编号。

考虑这个dfs序上两点之间的距离。设某个节点在dfs序中第一次出现的位置为$where_i$,第i个位置的节点为$what_i$两个点分别为u和v。可以发现,在dfs上,u和v之间一堆会包含它们的lca,则:

$$dis_{u,v}=max_{where_u \leq x \leq where_v}{\{dep_u+dep_v-2*dep_{what_x}\}}$$

树的直径即为上述表达式的最大值。

考虑到直径的形式为u-lca-v的形式,我们可以在dfs序上看成是L、M、R的这三部分组成,其中L和R要尽可能大,M要尽可能小(代码中先加了符号,所以还是最大的)。考虑线段树,维护当前区间的最大值、M、LM、MR和LMR,最后的答案即为线段树根节点的LMR。不难证明,可以进行如下合并:
$val=max{\{val_l,val_r\}}$

$M=max{\{M_l,M_r\}}$(取了负号)
$LM=max{\{LM_l,LM_r,val_l+M_r\}}$
$MR=max{\{RM_l,RM_r,M_l+val_r\}}$

$LMR=max{\{LMR_l,LMR_r,LM_l+val_r,val_l+RM_r\}}$

对于修改操作,相当于是区间修改,直接打标记即可。

时间复杂度:$O(n+qlogn)$


代码

 // luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int maxn=1E5+;
typedef long long int ll;
int n,m;
int size=,head[maxn*];
int dfn,dfnFirst[maxn],dfnLast[maxn],what[maxn*],fa[maxn];
ll lastans,weight[maxn],dep[maxn];
ll val[maxn*],M[maxn*],LM[maxn*],MR[maxn*],LMR[maxn*],tag[maxn*];
struct edge
{
int to,next;
ll w;
}E[maxn*];
inline void addE(int u,int v,ll w)
{
E[++size].to=v;
E[size].next=head[u];
E[size].w=w;
head[u]=size;
}
void dfs(int u,int F,ll d)
{
what[dfnFirst[u]=++dfn]=u;
dep[u]=d;
fa[u]=F;
for(int i=head[u];i;i=E[i].next)
{
int v=E[i].to;
if(v==F)
continue;
weight[v]=E[i].w;
dfs(v,u,d+E[i].w);
what[++dfn]=u;
}
dfnLast[u]=dfn;
}
inline void pushdown(int l,int r,int num)
{
val[num]+=tag[num];
M[num]-=tag[num]*;
LM[num]-=tag[num];
MR[num]-=tag[num];
if(l!=r)
tag[num<<]+=tag[num],tag[num<<|]+=tag[num];
tag[num]=;
}
inline void update(int l,int r,int num)
{
if(l==r)
return;
val[num]=max(val[num<<],val[num<<|]);
M[num]=max(M[num<<],M[num<<|]);
LM[num]=max(max(LM[num<<],LM[num<<|]),val[num<<]+M[num<<|]);
MR[num]=max(max(MR[num<<],MR[num<<|]),M[num<<]+val[num<<|]);
LMR[num]=max(max(LMR[num<<],LMR[num<<|]),max(LM[num<<]+val[num<<|],val[num<<]+MR[num<<|]));
}
void build(int l,int r,int num)
{
if(l==r)
{
int pos=what[l];
val[num]=dep[pos];
M[num]=-*dep[pos];
LM[num]=MR[num]=-dep[pos];
return;
}
int mid=(l+r)>>;
build(l,mid,num<<),build(mid+,r,num<<|);
update(l,r,num);
}
void add(int L,int R,int l,int r,ll x,int num)
{
if(L<=l&&r<=R)
{
tag[num]+=x;
pushdown(l,r,num);
return;
}
pushdown(l,r,num);
int mid=(l+r)>>;
if(R<=mid)
add(L,R,l,mid,x,num<<);
else if(mid<L)
add(L,R,mid+,r,x,num<<|);
else
add(L,R,l,mid,x,num<<),add(L,R,mid+,r,x,num<<|);
pushdown(l,mid,num<<);
pushdown(mid+,r,num<<|);
update(l,r,num);
}
int main()
{
ios::sync_with_stdio(false);
ll W;
cin>>n>>m>>W;
for(int i=;i<=n;++i)
{
int x,y;
ll z;
cin>>x>>y>>z;
addE(x,y,z);
addE(y,x,z);
}
dfs(,,);
build(,*n-,);
while(m--)
{
ll x,y;
cin>>x>>y;
x=(x+lastans)%(n-)+;
y=(y+lastans)%W;
if(fa[E[x<<].to]==E[x<<|].to)
x=E[x<<].to;
else
x=E[x<<|].to;
add(dfnFirst[x],dfnLast[x],,*n-,y-weight[x],);
weight[x]=y;
lastans=LMR[];
cout<<lastans<<endl;
}
return ;
}

[CF1192B]动态直径的更多相关文章

  1. 2019 ICPC上海网络赛 A 题 Lightning Routing I (动态维护树的直径)

    题目: 给定一棵树, 带边权. 现在有2种操作: 1.修改第i条边的权值. 2.询问u到其他一个任意点的最大距离是多少. 题解: 树的直径可以通过两次 dfs() 的方法求得.换句话说,到任意点最远的 ...

  2. 「校内训练 2019-04-23」越野赛车问题 动态dp+树的直径

    题目传送门 http://192.168.21.187/problem/1236 http://47.100.137.146/problem/1236 题解 题目中要求的显然是那个状态下的直径嘛. 所 ...

  3. iOS 实现脉冲雷达以及动态增减元素 By Swift-感谢分享

    Swift经过Xcode6 Beta4一版更新后,基本上已经可以作为生产工具了,虽然有一些地方和ObjC比起来要“落后”一些,但也无伤大雅.这里就用Xcode6 Beta4+iOS SDK 8.0开发 ...

  4. #6145. 「2017 山东三轮集训 Day7」Easy 动态点分治

    \(\color{#0066ff}{题目描述}\) JOHNKRAM 最近在参加 C_SUNSHINE 举办的聚会. C 国一共有 n 座城市,这些城市由 n−1 条无向道路连接.任意两座城市之间有且 ...

  5. 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆

    [BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...

  6. [LOJ#121]动态图连通性

    [LOJ#121]动态图连通性 试题描述 这是一道模板题. 你要维护一张无向简单图.你被要求加入删除一条边及查询两个点是否连通. 0:加入一条边.保证它不存在. 1:删除一条边.保证它存在. 2:查询 ...

  7. 0x63树的直径与最近公共祖先

    凉 bzoj1999 先把树的直径求出来,从左往右枚举,对于当前位置i,找到满足限制并且最远的点j,当前位置最大值就是max(i~j区间内除直径外的子树路径长度最大值,1~i的长度,j~n的长度) 然 ...

  8. 小程序开发笔记【五】---基于LBS附近动态查询

    实现思路 : 获取用户当前位置经纬度坐标 查询动态时将经纬度坐标传给后台 后端通过sql语句计算经纬度坐标之间的距离 // 附近20公里发的动态 按时间排序 let sql = `SELECT * , ...

  9. 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树

    题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...

随机推荐

  1. 支撑百万级并发,Netty如何实现高性能内存管理

    Netty作为一款高性能网络应用程序框架,实现了一套高性能内存管理机制 通过学习其中的实现原理.算法.并发设计,有利于我们写出更优雅.更高性能的代码:当使用Netty时碰到内存方面的问题时,也可以更高 ...

  2. mysql中information_schema.columns字段说明

    1. 获取所有列信息(COLUMNS) SELECT  *  FROM information_schema.COLUMNS WHERE  TABLE_SCHEMA='数据库名';  COLUMNS表 ...

  3. java 使用 apoi 更新 ppt 中图表的数据

    本文源码:    1. https://github.com/zhongchengyi/zhongcy.demos/tree/master/apoi-ppt-chart 2. 在第5节也有核心源码 1 ...

  4. 012 Ceph多区域网关

    一.基本概念 1.1 多区域概念 Multi-Size功能是从J版本开始的.一个single zone配置通常由一个zone group组成,该zone group包含一个zone和多个用于负载均衡的 ...

  5. beta week 1/2 Scrum立会报告+燃尽图 01

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2019fall/homework/9911 git地址:https://e.coding.net/Eustia ...

  6. CSP201803-4棋局评估

    问题描述 Alice和Bob正在玩井字棋游戏. 井字棋游戏的规则很简单:两人轮流往3*3的棋盘中放棋子,Alice放的是“X”,Bob放的是“O”,Alice执先.当同一种棋子占据一行.一列或一条对角 ...

  7. 「Luogu P4987」回文项链 解题报告

    题面 求环中的长度为k(k为奇数)且回文中心不同的回文串个数 思路: 刚学manacher算法,就送上一道模板题,此题注重对manacher算法的理解 Manacher,但是不用插入其他符号,因为k是 ...

  8. bootstrap:导航分页

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...

  9. 输入URI,按下回车发生了什么?

    当我们输入URL,按下回车发生了什么? 这个题目很俗套- -但是是面试经常出现的题目了.今天听尼古拉斯•屌•大斌哥介绍关于从URI到浏览器呈现给我们页面发生了什么.感觉收获颇多.索性就翻阅了一些其他资 ...

  10. 《C++Primer》第五版习题答案--第二章【学习笔记】

    C++Primer第五版习题解答---第二章 ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/9 第二章:变量和基本类型 练习2.1: 类 ...