SS241017C. 距离(distance)

news/2024/10/18 15:57:48/文章来源:https://www.cnblogs.com/liyixin0514/p/18474437

SS241017C. 距离(distance)

题意

给你一棵无根树,边有边权。每次操作向集合 \(S\) 里插入一个点对 \((a,b)\) 或询问一个点对 \((x,y)\)。对于询问求 \(\min_{(a,b)\in S} \{dis(a,x)+dis(b,y)\}\)

solution

先考虑单点插入查询的情况。

相当于存在插入关键点操作,每次询问一个点距离最近的关键点。

好像是个经典题,但是我没做过。处理这样的路径问题可以想到点分治。

每个点分治重心可以处理出离它最近的关键点,因为待修且多次询问,就建出点分树。每次修改 \(\log\) 个点分治祖先,每次询问询问 \(\log\) 层。

这样询问是正确的,因为如果最近的关键点不在你的点分治子树里,离你的点分治祖先最近的结点一定离你最近。因为你必须经过祖先才能到达它。

考虑扩展到点对。首先所有关键点的信息都可以通过维护 \(\log\) 个祖先得到。

\(\min(dis(a,x)+dis(b,y))\),可以搞出它们在点分树上的祖先,算 \(\min(dis(a,p)+dis(x,p)+dis(b,q)+dis(y,q))=\min(dis(a,p)+dep(b,q)+dis(x,p)+dis(y,q))\),因此可以对插入和询问枚举祖先 \(p,q\),一共有 \(\log^2\) 对。插入就更新这些祖先对的答案,询问就取 \(\min\) 这些祖先对的答案。

可以在线做,时间和空间都是 \(n\log^2\) 的,但是要使用 \(map\) 映射,容易被卡常。

考虑离线优化空间。

我们一共会用到 \(n\log^2\)\((p,q)\),可以先离线出要用到哪些 \((p,q)\),然后对于每个 \(p\) 存下对应的 \((a,b)/(x,y)\),这样空间是 单 \(\log\) 的,先不存 \(p\)

然后枚举每个 \(p\),对于固定的 \(p\),按时间枚举存下的 \((a,b)/(x,y)\),然后更新或者查询 \(\log\)\(q\),这里的点分树空间是 \(O(n)\) 的。枚举下一个 \(p\) 的时候清空点分树。

总时间复杂度 \(O(n \log^2 n)\),空间 \(O(n\log n)\)

code

#include<bits/stdc++.h>
// #define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
using namespace std;
typedef long long ll;
constexpr int N=2e5+7,intinf=0x3f3f3f3f;
constexpr ll llinf=0x3f3f3f3f3f3f3f3f;
#define isdigit(x) (x>='0'&&x<='9')
template <typename T>
inline void read(T &x) {x=0;char ch=getchar();for(;!isdigit(ch);ch=getchar());for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}
template <typename T>
inline void write(T x,char ch) {static int st[20];int top=0;do {st[top++]=x%10;x/=10;}while(x);while(top) putchar(st[--top]+'0');putchar(ch);
}
int op,n,m,u,v,w;
struct edge {int to,ne,w;
}e[N<<1];
int cnt,head[N];
void addedge(int u,int v,int w) { e[++cnt]={v,head[u],w}, head[u]=cnt; }
template <typename T>
void _min(T &a,T b) { a=min(a,b); }
template <typename T>
void _max(T &a,T b) { a=max(a,b); }
int dfn[N],gfa[N];
int st[N][20];
ll dep[N];
void dfs(int u,int f) {dfn[u]=++dfn[0]; st[dfn[0]][0]=f;for(int i=head[u];i;i=e[i].ne) {int v=e[i].to;if(v==f) continue;dep[v]=dep[u]+e[i].w;dfs(v,u);}
}
int lcamin(int x,int y) { return dfn[x]<dfn[y]?x:y; }
void lcainit() {int lg=__lg(n);rep(k,1,lg) for(int i=1;i+(1<<k)-1<=n;i++) st[i][k]=lcamin(st[i][k-1],st[i+(1<<(k-1))][k-1]);
}
int getlca(int u,int v) {if(u==v) return u;int mnx=min(dfn[u],dfn[v])+1,mxx=max(dfn[u],dfn[v]);int lg=__lg(mxx-mnx+1);return lcamin(st[mnx][lg],st[mxx-(1<<lg)+1][lg]);
}
bool del[N];
int rt,mnrt;
int sum;
int sz[N];
void getroot(int u,int f) {sz[u]=1;int mxsz=0;for(int i=head[u];i;i=e[i].ne) {int v=e[i].to;if(v==f||del[v]) continue;getroot(v,u);sz[u]+=sz[v];_max(mxsz,sz[v]);}_max(mxsz,sum-sz[u]);if(mxsz<mnrt) rt=u,mnrt=mxsz;
}
void buildtree(int u) {del[u]=1;for(int i=head[u];i;i=e[i].ne) {int v=e[i].to;if(del[v]) continue;sum=sz[v];rt=0;mnrt=intinf;getroot(v,0);gfa[rt]=u;buildtree(rt);}
}
ll getdis(int u,int v) {int lca=getlca(u,v);return dep[u]+dep[v]-2*dep[lca];
}
ll ans[N];
ll f[N];
void init() {memset(ans,0x3f,sizeof(ans));memset(f,0x3f,sizeof(f));dfs(1,0);lcainit();sum=n;mnrt=intinf;getroot(1,0);buildtree(rt);
}
struct node {int op,u,v;
}que[N];
vector<int> vec[N];
void initadd(int u,int i) {for(int x=u;x;x=gfa[x]) vec[x].push_back(i);
}
void insert(int u,int a,int b) {for(int x=b;x;x=gfa[x]) _min(f[x],getdis(a,u)+getdis(b,x));
}
ll query(int u,int a,int b) {ll ans=llinf;for(int x=b;x;x=gfa[x]) _min(ans,f[x]+getdis(b,x));ans+=getdis(u,a);return ans;
}
void clear(int u,int a,int b) {for(int x=b;x;x=gfa[x]) f[x]=llinf;
}
int main() {#ifdef LOCAL// freopen("my.out","w",stdout);#elsefreopen("distance.in","r",stdin);freopen("distance.out","w",stdout);#endifread(n),read(m);rep(i,1,n-1) {read(u),read(v),read(w);addedge(u,v,w),addedge(v,u,w);}init();rep(i,1,m) {read(op),read(u),read(v);que[i]={op,u,v};initadd(u,i);}rep(i,1,n) {for(int x:vec[i]) {int op=que[x].op,u=que[x].u,v=que[x].v;if(op==1) insert(i,u,v);else _min(ans[x],query(i,u,v));}for(int x:vec[i]) {if(que[x].op==1) clear(i,que[x].u,que[x].v);}}rep(i,1,m) if(que[i].op==2) {if(ans[i]==ans[0]) puts("-1");else write(ans[i],'\n');}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/816918.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins+Coverage的代码覆盖率集成实践

Jenkins+Coverage的代码覆盖率集成实践 一、工具介绍Jenkins: Jenkins是一个开源的、基于Java开发的持续集成工具,它可以帮助开发人员自动化构建、测试和部署软件项目。 Coverage: Coverage是一个Python代码覆盖率工具,用于测量代码执行过程中哪些代码行被执行到,从而评估…

C++顺序结构(3)、数据类型_____教学

一、设置域宽setw() 输出的内容所占的总宽度成为域宽,有些高级语言中称为场宽。 使用setw()前,必须包含头文件iomanip,即#include<iomanip> 头文件iomanip,用来声明一些“流操作符”,需要一定格式输入输出时,就需要用到它,比较常用的有设置域宽、设置左右对齐、设置…

OpenCity: Open Spatio-Temporal Foundation Models for Traffic Prediction

1. 数据准备 在这个数据处理过程中,以数据集 PEMS07M 为例,整个数据抽取和划分过程如下:初始数据维度:原始训练数据 data_train 的维度为 (12672, 228, 3)。其中:12672 表示时间步数,代表不同的时间点采样的数据。 228 表示空间节点数(例如不同的交通站点)。 3 表示每个…

04C++顺序结构(3)

1、设置域宽setw(); 2、cin语句; 3、输入输出.格式化一、设置域宽setw() 输出的内容所占的总宽度成为域宽,有些高级语言中称为场宽。 使用setw()前,必须包含头文件iomanip,即#include<iomanip> 头文件iomanip,用来声明一些“流操作符”,需要一定格式输入输出时,就…

轻松上手-MVVM模式_关系型数据库_云函数T云数据库

作者:狼哥 团队:坚果派 团队介绍:坚果派由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉。团队成员聚集在北京,上海,南京,深圳,广州,宁…

九宫格自由流转拼图游戏

作者:狼哥 团队:坚果派 团队介绍:坚果派由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉。团队成员聚集在北京,上海,南京,深圳,广州,宁…

数据预处理-DataFrame切片

此Blog仅作为日常学习工作中记录使用,Blog中有不足之处欢迎指出 以kaggle中房屋预测的训练集为例,说明DataFrame切片常用操作 一、读入数据 import numpy as np import pandas as pdfile_path = ***\kaggle_house_pred_train.csv data = pd.read_csv(file_path)data.columns …

轻松上手-Navigation路由 H5

作者:狼哥 团队:坚果派 团队介绍:坚果派由坚果等人创建,团队拥有12个华为HDE带领热爱HarmonyOS/OpenHarmony的开发者,以及若干其他领域的三十余位万粉博主运营。专注于分享HarmonyOS/OpenHarmony、ArkUI-X、元服务、仓颉。团队成员聚集在北京,上海,南京,深圳,广州,宁…

Audio

音频文件导入 常用格式wav mp3 aiff音频文件属性设置Force To Mono:多声道转单声道; Normalize:强制为单声道时,混合过程中被标准化 Load In Background:在后台加载时,不阻塞主线程 Ambisonic:立体混响声,非常适合360度视频和XR应用程序,如果音频文件包含立体混响声编…

RenderTexture

基础概念 RenderTexture 在Unity中,RenderTexture是一种纹理,它可以在运行时动态地生成图像数据,并且可以作为着色器的输入或者显示在游戏世界的任何材质上。简单来说,RenderTexture让你能够将场景或特定相机的渲染结果捕获到一个纹理中,然后这个纹理可以被用作其他渲染过…

九点共圆及其圆心证明(证明过程已更新)

九点共圆及其圆心证明主要思路:固定 \(P,L\),证明其它七个点均在以 \(PL\) 为直径的圆上。 条件的来源会备注在括号内。背景可能影响观感,建议打开极简模式阅读。这是一个三角形 \(\triangle ABC\),设 \(BC,AC,AB\) 边上垂足分别为 \(D,E,F\),其边上中点分别为 \(L,M,N\),…

【喜讯】全球电商大数据平台推出F类免费API接口服务!

好消息,全球电商大数据平台再次上线多个类别接口,首次推出F类免费API接口服务,为所有追求数据赋能、寻求创新突破的企业和个人,带来了前所未有的机遇。好消息,值此之际;全球电商大数据平台再次上线多个类别接口,首次推出F类免费API接口服务,为所有追求数据赋能、寻求创…