[CF1192B]动态直径
题意
给一棵固定形态的树,边有边权,每次修改一条边权,在线求出修改后树的直径。
思考
写出树的全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]动态直径的更多相关文章
- 2019 ICPC上海网络赛 A 题 Lightning Routing I (动态维护树的直径)
题目: 给定一棵树, 带边权. 现在有2种操作: 1.修改第i条边的权值. 2.询问u到其他一个任意点的最大距离是多少. 题解: 树的直径可以通过两次 dfs() 的方法求得.换句话说,到任意点最远的 ...
- 「校内训练 2019-04-23」越野赛车问题 动态dp+树的直径
题目传送门 http://192.168.21.187/problem/1236 http://47.100.137.146/problem/1236 题解 题目中要求的显然是那个状态下的直径嘛. 所 ...
- iOS 实现脉冲雷达以及动态增减元素 By Swift-感谢分享
Swift经过Xcode6 Beta4一版更新后,基本上已经可以作为生产工具了,虽然有一些地方和ObjC比起来要“落后”一些,但也无伤大雅.这里就用Xcode6 Beta4+iOS SDK 8.0开发 ...
- #6145. 「2017 山东三轮集训 Day7」Easy 动态点分治
\(\color{#0066ff}{题目描述}\) JOHNKRAM 最近在参加 C_SUNSHINE 举办的聚会. C 国一共有 n 座城市,这些城市由 n−1 条无向道路连接.任意两座城市之间有且 ...
- 【BZOJ1095】[ZJOI2007]Hide 捉迷藏 动态树分治+堆
[BZOJ1095][ZJOI2007]Hide 捉迷藏 Description 捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子.某天,Jiajia.Wind和孩子们决定在家里玩捉 ...
- [LOJ#121]动态图连通性
[LOJ#121]动态图连通性 试题描述 这是一道模板题. 你要维护一张无向简单图.你被要求加入删除一条边及查询两个点是否连通. 0:加入一条边.保证它不存在. 1:删除一条边.保证它存在. 2:查询 ...
- 0x63树的直径与最近公共祖先
凉 bzoj1999 先把树的直径求出来,从左往右枚举,对于当前位置i,找到满足限制并且最远的点j,当前位置最大值就是max(i~j区间内除直径外的子树路径长度最大值,1~i的长度,j~n的长度) 然 ...
- 小程序开发笔记【五】---基于LBS附近动态查询
实现思路 : 获取用户当前位置经纬度坐标 查询动态时将经纬度坐标传给后台 后端通过sql语句计算经纬度坐标之间的距离 // 附近20公里发的动态 按时间排序 let sql = `SELECT * , ...
- 2019ICPC上海网络赛 A Lightning Routing I 点分树(动态点分治)+线段树
题意 给一颗带边权的树,有两种操作 \(C~e_i~w_i\),将第\(e_i\)条边的边权改为\(w_i\). \(Q~v_i\),询问距\(v_i\)点最远的点的距离. 分析 官方题解做法:动态维 ...
随机推荐
- int32 无符号范围 -2147483648~2147483647
int32 无符号范围 -2147483648~2147483647
- 关于C#异步编程你应该了解的几点建议
前段时间写了一篇关于C#异步编程入门的文章,你可以点击<C#异步编程入门看这篇就够了>查看.这篇文章我们来讨论下关于C#异步编程几个不成文的建议,希望对你写出高性能的异步编程代码有所帮助. ...
- Visual Studio 2019使用docker开发(vsdbg的问题)
前言 vsdbg在国内下载的速度真的很慢,借助迅雷也没办法起飞. 这里还是来探讨下如何用迅雷进行下载以后安装操作. 遇到的状况 在使用Visual Studio 2019进行开发调试(https:// ...
- DRF 06
目录 视图家族 views视图类 mixin视图工具类 generics工具视图类 viewsets视图集 路由配置 视图家族 views视图类 APIView """ ...
- 日期格式化跨年bug,是否与你不期而遇?
2020年来临之前,日期格式化操作也为程序员准备了一个跨年级别的bug,不知你的系统是否遇到? 临近2020年元旦的几天,不少网站出现了类似2020/12/29,2020/12/30,2020/12/ ...
- 关于Mac VMFusion Centos7虚拟机网络的配置
1.环境配置: 创建完快照后启动虚拟机,使用root用户和root密码登录系统 1.1 停止防火墙 #停止防火墙 [root@localhost ~]#systemctl stop firewalld ...
- 编译GLib C程序
编译GLib C程序 GLib是GTK +所需的实用程序库,但也可以在非GUI应用程序中独立使用.本文介绍如何在Linux中编译使用GLib的C程序.它还显示了如何为系统上安装的GLib版本安装正确的 ...
- JAVA8学习——深入Comparator&Collector(学习过程)
深入Comparator&Collector 从源码深入Comparator Comparator从Java1.2就出来了,但是在1.8的时候,又添加了大量的默认方法. compare() e ...
- 1062 最简分数 (20分)C语言
一个分数一般写成两个整数相除的形式:N/M,其中 M 不为0.最简分数是指分子和分母没有公约数的分数表示形式. 现给定两个不相等的正分数 N1/M1和 N2/M2,要求你按从小到大的顺序列出它们之间 ...
- Java 多线程与并发(六):AQS
我们前面几张提到过,JUC 这个包里面的工具类的底层就是使用 CAS 和 volatile 来保证线程安全的,整个 JUC 包里面的类都是基于它们构建的.今天我们介绍一个非常重要的同步器,这个类是 J ...