P6845 [CEOI2019] Dynamic Diameter

题意

一颗带权树,每次更改一条边的权,每次修改后求出最大直径。强制在线。

思路

\(O(n\log^2n)\) 的暴力做法。

根据经典结论,对于两个点集的树上最大直径(权值非负),并集点集的树上最大直径的端点一定是原四个端点中的两个。

那么我们就可以用线段树维护点集,合并时 \(O(\log n)\) 查询两点间距离合并就可以做到 \(O(n\log^2n)\) 的复杂度了。

思考如何支持在线修改边权。两点间距离为 \(dis(x)+dis(y)-2*dis(lca(x,y))\) 那么先树剖发现修改一条边的权实际上是将子树内 \(dis\) 增加,那么子树就是区间加。我们可以用树状数组维护修改。

考虑哪些部分的线段树上的点集最大直径被改了。发现子树内和子树外的最大直径不会变化,那么我们只需要更改子树内与外之间合并的最大直径就行了。我们按照 \(dfn\) 用线段树进行维护,那么我们每次只需要将子树区间重新 pushup 一下就可以了。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<cstdlib>
#include<utility>
using namespace std;
inline long long read(){
long long x=0;int w=0;char c=getchar();
while(!isdigit(c)) w|=c=='-',c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return w?-x:x;
}
namespace star
{
const int maxn=1e5+10;
int n,q;
int ecnt=1,head[maxn],to[maxn<<1],nxt[maxn<<1],go[maxn];
long long W,w[maxn],dis[maxn];
inline void addedge(){
int a=read(),b=read();
to[++ecnt]=b,nxt[ecnt]=head[a],head[a]=ecnt;
to[++ecnt]=a,nxt[ecnt]=head[b],head[b]=ecnt;
w[ecnt>>1]=read();
}
int dep[maxn],fa[maxn],top[maxn],siz[maxn],son[maxn],dfn[maxn],id[maxn];
void dfs1(int x,int f){
fa[x]=f,dep[x]=dep[f]+1,siz[x]=1;
for(int u,i=head[x];i;i=nxt[i]) if((u=to[i])!=f){
dis[u]=dis[x]+w[i>>1],dfs1(u,x),go[i>>1]=u;
if(siz[u]>siz[son[x]]) son[x]=u;
siz[x]+=siz[u];
}
}
void dfs2(int x,int topf){
top[x]=topf,dfn[x]=++dfn[0],id[dfn[0]]=x;
if(!son[x]) return;
dfs2(son[x],topf);
for(int u,i=head[x];i;i=nxt[i]) if((u=to[i])!=fa[x] and u!=son[x]) dfs2(u,u);
}
inline int LCA(int x,int y){
while(top[x]!=top[y]) dep[top[x]]>dep[top[y]]?(x=fa[top[x]]):(y=fa[top[y]]);
return dep[x]<dep[y]?x:y;
}
#define ls (ro<<1)
#define rs (ro<<1|1)
#define mid ((l+r)>>1)
namespace S{
long long c[maxn];
inline void upd(int x,long long k){for(;x<=n;x+=x&-x) c[x]+=k;}
inline long long query(int x){long long ans=dis[id[x]];for(;x;x-=x&-x) ans+=c[x];return ans;}
inline void update(int x,int y,long long w){upd(x,w),upd(y+1,-w);}
}
inline long long Dis(pair<int,int> a){return S::query(dfn[a.first])+S::query(dfn[a.second])-2*S::query(dfn[LCA(a.first,a.second)]);}
namespace T{
pair<int,int> e[maxn<<2];
inline pair<int,int> merge(const pair<int,int>& a,const pair<int,int>& b){
pair<int,int> p[6]={a,b,make_pair(a.first,b.first),make_pair(a.first,b.second),make_pair(a.second,b.first),make_pair(a.second,b.second)};
long long dis[6];
for(int i=0;i<6;i++) dis[i]=Dis(p[i]);
return p[max_element(dis,dis+6)-dis];
}
void build(int ro=1,int l=1,int r=n){
if(l==r) return e[ro]=make_pair(id[l],id[l]),void();
build(ls,l,mid),build(rs,mid+1,r);
e[ro]=merge(e[ls],e[rs]);
}
void update(int x,int y,int ro=1,int l=1,int r=n){
if(x==l and y==r) return;
if(y<=mid) update(x,y,ls,l,mid);
else if(x>mid) update(x,y,rs,mid+1,r);
else update(x,mid,ls,l,mid),update(mid+1,y,rs,mid+1,r);
e[ro]=merge(e[ls],e[rs]);
}
}
#undef ls
#undef rs
#undef mid
inline void work(){
n=read(),q=read(),W=read();
for(int i=1;i<n;i++) addedge();
dfs1(1,0),dfs2(1,1);
T::build();
long long ans=0;
while(q--){
int e=(read()+ans)%(n-1)+1;
long long v=(read()+ans)%W;
S::update(dfn[go[e]],dfn[go[e]]+siz[go[e]]-1,v-w[e]),w[e]=v;
T::update(dfn[go[e]],dfn[go[e]]+siz[go[e]]-1);
printf("%lld\n",ans=Dis(T::e[1]));
}
}
}
signed main(){
star::work();
return 0;
}

P6845 [CEOI2019] Dynamic Diameter的更多相关文章

  1. CEOI2019 / CodeForces 1192B. Dynamic Diameter

    题目简述:给定一棵$N \leq 10^5$个节点的树,边上带权,维护以下两个操作: 1. 修改一条边的边权: 2. 询问当前树的直径长度. 解1:code 注意到树的直径有以下性质: 定理:令$\t ...

  2. NOIP前做题记录

    鉴于某些原因(主要是懒)就不一题一题写了,代码直接去\(OJ\)上看吧 CodeChef Making Change 传送门 完全没看懂题解在讲什么(一定是因为题解公式打崩的原因才不是曲明英语太差呢- ...

  3. Diameter协议摘要

    ---------选择同学整理文档 1.   协议概述 Diameter协议主要为应用程序提供认证.鉴权.计费框架,即AAA,并支持本地AAA和漫游场景下的AAA. 1.1.  特点介绍 以前的AAA ...

  4. var和dynamic的区别

    1.var 1.均是声明动态类型的变量. 2.在编译阶段已经确定类型,在初始化的时候必须提供初始化的值. 3.无法作为方法参数类型,也无法作为返回值类型. 2.dynamic 1.均是声明动态类型的变 ...

  5. 遍历dynamic的方式

    一.遍历ExpandoObject /// <summary> /// 遍历ExpandoObject /// </summary> [TestMethod] public v ...

  6. C# dynamic 动态创建 json

    1. 如何通过C# 的dynamic 创建如下json 对象? { "query": { "match": [{ "name": " ...

  7. BZOJ 1901: Zju2112 Dynamic Rankings[带修改的主席树]【学习笔记】

    1901: Zju2112 Dynamic Rankings Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 7143  Solved: 2968[Su ...

  8. 当类型为dynamic的视图模型遭遇匿名对象

    当年在ASP.NET MVC 1.0时代我提到,在开发时最好将视图的Model定制为强类型的,这样可以充分利用静态检查功能进行排错.不过有人指出,这么做虽然易于静态检查,但是定义强类型的Model类型 ...

  9. 动态规划 Dynamic Programming

    March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...

随机推荐

  1. IOS小组件(8):App与Widget数据共享

    引言   Widget是一个迷你版的App,IOS有沙盒机制,不同App之间无法直接共享数据.组件和主App之间其实就是不同App的关系,所以也无法通过userdefaults.standard来传数 ...

  2. Mysql数据库值的添加、修改、删除及清空

    3.MySQL数据管理 第一种方式:不太建议,看起来复杂些 -- 学生表的 gradeid 字段,要去引用 年级表的 gradeid -- 定义外键key -- 给这个外键添加约束,(执行引用),RE ...

  3. 如何避免Nginx将url decode

    灵感来自:https://my.oschina.net/jastme/blog/528541 这是最近玩微服务架构遇到的一个情况,因为Spring Boot 1.5的网关不支持websocket的转发 ...

  4. Binding(一):数据绑定

    这节开始分几期来讲一下WPF中Binding的相关用法,本节主要讲使用Binding进行数据绑定. Binding的作用 在WinForm中,我们要想对控件赋值,需要在后台代码中拿到控件对象进行操作, ...

  5. NOIP模拟测试26「嚎叫响彻在贪婪的机房·主仆见证了 Hobo 的离别·征途堆积出友情的永恒」

    题目比较神仙,注意是题目神仙 贪婪暗示贪心,堆积暗示堆优化$\%\%\%\%\%\%\%$ 两个乱搞$+$一个堆优化$dp$ 嚎叫响彻在贪婪的机房 题解 对于一个序列来说只要他们差的$gcd$不为$1 ...

  6. 关于MySql数据库误操作数据找回的办法

    先讲个事,前段时间,系统长时间不用的一个功能被开放出来了,想当然的我没有在测试平台上测试,直接操作了正式系统(的确是我不严谨),导致好多数据异常,页面展示错乱了.于是我想到的第一个就是进行备份还原.项 ...

  7. 详解Redis主从复制原理

    文章首发于公众号 "蘑菇睡不着" 前言 Redis 的主从复制和 MySQL 差不多,主要起着 数据备份,读写分离等作用.所以说主从复制对 Redis 来说非常重要,而无论是面试还 ...

  8. 二QT中使用QTimer定时器

    QT中的定时器类叫QTimer(5.8以上版本才有),构造函数只需要提供父对象的指针 使用的话,需要调用QTImer的start方法,该方法以毫秒单位,每过指定毫秒时间,该类对象就会发出一个timeo ...

  9. 10、mysql增量恢复实战

    10.1.实验数据: mysql> select * from test; +----+------+------+ | id | name | age | +----+------+----- ...

  10. Redis:Java链接redis单节点千万级别数据 写入,读取 性能测试

    本文是对Redis 单节点,针对不同的数据类型,做插入行测试. 数据总条数为:10058624 环境说明:             Redis 未做任何优化, 单节点    (服务器上, 内存64G) ...