题意:给你一个含n条边的带权无向连通图,q次查询,每次查询两点间的最短距离。

思路:LCA+思维。

设a,b两点间的距离为f(a,b) 则f(a,b)=dis[a]+dis[b]-2*dis[lca(a,b)];

由于n条边,因此我们先任取一条边,设这条边为X,Y,权值为Z,设查询的点为x,y,则答案为

min(f(a,b),f(a,X)+f(b,X),f(a,Y)+f(b,Y),f(a,X)+f(b,Y)+Z,f(a,Y)+f(b,X)+Z);

#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)using namespace std;
typedef long long ll;
const int N =1e5+5;struct node
{int u,v,next;int id,f;ll w;
}edge[N*2];struct node1
{int l,r;ll w;ll lz;
}tr[N<<2];int tot,head[N];
int n,q;
int anc[N<<1][20];int dfn;
int dfns[N*2];
int dep[N*2];
int pos[N];
int inde[N];
int L[N];
int R[N];
int clo;int to[N];
int vis[N];
ll ww[N];int uu,vv;
ll cost;
int huan;
int idd;void init()
{tot=0;memset(head,-1,sizeof(head));memset(vis,0,sizeof(vis));memset(inde,-1,sizeof(inde));memset(pos,-1,sizeof(pos));clo=0; huan=0; idd=0; dfn=0;  /// dfn竟然没清零 MMP
}void add(int u,int v,ll w,int id)
{edge[++tot].u=u; edge[tot].v=v; edge[tot].id=id; edge[tot].w=w; edge[tot].f=0;edge[tot].next=head[u]; head[u]=tot;
}void dfs1(int u,int fa)
{if(vis[u]){uu=fa; vv=u; huan=1; return ;}vis[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==fa) continue;dfs1(v,u);}
}void dfs2(int u,int deep) /// dfs序
{//cout<<" u "<<u<<" deep "<<deep<<endl;dfns[dfn]=u; dep[dfn]=deep; pos[u]=dfn++;L[u]=++clo;inde[u]=L[u]; /// 记录u在线段树中的位置for(int i=head[u];i!=-1;i=edge[i].next){if(edge[i].f) continue;  /// 如果是标记的边跳过int v=edge[i].v;if(pos[v]==-1){to[edge[i].id]=v; /// 表示这条边指向哪个点?dfs2(v,deep+1);dfns[dfn]=u; dep[dfn++]=deep;}}R[u]=clo;
}void init_RMQ(int n)  /// dfn
{for(int i=1;i<=n;++i) anc[i][0]=i;for(int j=1;(1<<j)<=n;++j)for(int i=1;i+(1<<j)-1<=n;++i){if(dep[anc[i][j-1]]<dep[anc[i+(1<<(j-1))][j-1]]) anc[i][j]=anc[i][j-1];else anc[i][j]=anc[i+(1<<(j-1))][j-1];}
}inline int RMQ(int L,int R)
{int k=0;while(1<<(k+1)<=R-L+1) ++k;if(dep[anc[L][k]]<dep[anc[R-(1<<k)+1][k]]) return anc[L][k];return anc[R-(1<<k)+1][k];
}inline int LCA(int u,int v)
{if(pos[u]>pos[v]) return dfns[RMQ(pos[v],pos[u])];return dfns[RMQ(pos[u],pos[v])];
}void push_up(int i)
{tr[i].w=tr[lson].w+tr[rson].w;
}void push_down(int i)
{if(tr[i].lz){ /// 查询只有点查询,所以不必更新区间点的sumll &lz=tr[i].lz;tr[lson].lz+=lz; tr[rson].lz+=lz;tr[lson].w+=lz;  tr[rson].w+=lz;lz=0;}
}void build(int i,int l,int r)
{tr[i].l=l; tr[i].r=r; tr[i].w=0; tr[i].lz=0;if(l==r) return ;int mid=(l+r)>>1;build(lson,l,mid);build(rson,mid+1,r);
}void update(int i,int l,int r,ll w)
{if(tr[i].l==l&&tr[i].r==r){tr[i].lz+=w; tr[i].w+=w;return ;}push_down(i);int mid=(tr[i].l+tr[i].r)>>1;if(r<=mid) update(lson,l,r,w);else if(l>mid ) update(rson,l,r,w);else{update(lson,l,mid,w);update(rson,mid+1,r,w);}push_up(i);
}ll query(int i,int aim)
{if(tr[i].l==tr[i].r&&tr[i].l==aim){return tr[i].w;}push_down(i);int mid=(tr[i].l+tr[i].r)>>1;if(aim<=mid) return query(lson,aim);else return query(rson,aim);
}ll getans(int u,int v)
{int lca=LCA(u,v);ll sum1,sum2,sum3;sum1=query(1,L[u]); sum2=query(1,L[v]);sum3=query(1,L[lca]);return sum1+sum2-sum3*2;
}int main()
{int T;int u,v,op;ll w;scanf("%d",&T);while(T--){scanf("%d %d",&n,&q);init();for(int i=1;i<=n;i++){scanf("%d %d %lld",&u,&v,&w);add(u,v,w,i);add(v,u,w,i);ww[i]=w;}dfs1(1,-1);/// 第一遍dfs 先找到环中的任意一条边for(int i=1;i<=tot;i++){  /// 给边打上标记if((edge[i].u==uu&&edge[i].v==vv)||(edge[i].u==vv&&edge[i].v==uu)){edge[i].f=1;idd=edge[i].id;cost=edge[i].w;}}dfs2(1,0);/*cout<<"dfn "<<dfn<<endl;cout<<uu<<" *** "<<vv<<endl;for(int i=1;i<=n;i++){cout<<"l "<<L[i]<<" r "<<R[i]<<endl;}*/init_RMQ(dfn);build(1,1,n);  /// 以dfs的遍历出的 L,R 建树  那么接下来就是一个区间更新,单点查询的问题了for(int i=1;i<=n;i++){if(i==idd) continue;u=to[i];update(1,L[u],R[u],ww[i]);}/*for(int i=1;i<=n;i++){ll tmp=query(1,L[i]);cout<<" dis "<<tmp<<endl;}*/while(q--){scanf("%d %d",&u,&v);ll ans=getans(u,v);ans=min(ans,getans(uu,u)+getans(vv,v)+cost); /// 经过标记的路的两个不同的方向。ans=min(ans,getans(uu,v)+getans(vv,u)+cost);printf("%lld\n",ans);}}return 0;
}

View Code

转载于:https://www.cnblogs.com/shuaihui520/p/10439993.html

CF :K 一个含n条边的带权无向连通图,q次查询,每次查询两点间的最短距离。...相关推荐

  1. python不放回抽样_Python实现一个带权无回置随机抽选函数的方法

    需求 有一个抽奖应用,从所有参与的用户抽出K位中奖用户(K=奖品数量),且要根据每位用户拥有的抽奖码数量作为权重. 如假设有三个用户及他们的权重是: A(1), B(1), C(2).希望抽到A的概率 ...

  2. 一个含n个顶点和e条弧的有向图以邻接矩阵表示法为存储结构,则计算该有向图中某个顶点出度的时间复杂度为

    一个含n个顶点和e条弧的有向图以邻接矩阵表示法为存储结构,则计算该有向图中某个顶点出度的时间复杂度为(       ) A.O(n)                                   ...

  3. 代码资源网整站完整代码,基于ripro9.0定制开发,含572条精品资源数据

    许多网友都想搭建一个资源网站,有些网友购买网站vip会员,然后再每天搬运代码资源再整理上传到自己的网站上去,实在太麻烦太辛苦. 鉴于此种需求,本人决定把本站到目前为止的数据整体打包,分享给大家,让大家 ...

  4. 分段函数是不是一定初等函数_查漏补缺问题64:一个含多参数分段函数的连续性与可导性讨论...

    一个含多参数分段函数的连续性与可导性讨论 题目: 设, 定义函数 (1) 讨论当满足什么条件时,函数在0点连续. (2) 讨论当满足什么条件时,函数在0点可导. (3) 讨论当满足什么条件时,函数的导 ...

  5. Java黑皮书课后题第4章:*4.5(几何:正多边形的面积)正多边形是一个具有n条边的多边形,它每条边的长度都相等,而且所有角的度数也相等。编写程序,提示用户数输入边个数和边长,然后显示它的面积

    *4.5(几何:正多边形的面积)正多边形是一个具有n条边的多边形,它每条边的长度都相等,而且所有角的度数也相对.编写程序,提示用户数输入边个数和边长,然后显示它的面积 题目 题目概述 运行示例 代码 ...

  6. bootstrap 导航菜单 折叠位置_教大家如何编写一个网页导航条

    导航条简单地说就是对你整个网站模块的简单介绍,你可以直接点击导航条某一个按钮或板块便可进入其相应的界面,如:网页.新闻.贴吧等 .在企业网站上,导航条上常见的有:产品介绍,公司简介,最新产品,联系我们 ...

  7. SQL 拼接多个字段的值一个字段多条记录的拼接

    例如student表: studentID studentName studentScore 01 Alice 90 02 Bill 95 03 Cindy 100 一.拼接多个字段的值 select ...

  8. 【408计算机考研】|【2018统考真题-41】| 给定一个含 n(n≥1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数

    目录 一.题目 二.解答 三.测试数据 一.题目   给定一个含 n(n≥1)个整数的数组,请设计一个在时间上尽可能高效的算 法,找出数组中未出现的最小正整数.例如,数组{-5, 3, 2, 3}中未 ...

  9. 给定一个含n(n≥1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。

    笔者初涉<算法设计与分析>这门专业课,在做一些算法设计题的过程中遇到一些小感悟,特此记录和大家分享. 下面直接给出算法题目: 给定一个含n(n≥1)个整数的数组,请设计一个在时间上尽可能高 ...

最新文章

  1. springboot获取resources路径_Docker构建SpringBoot应用
  2. CTFshow php特性 web112
  3. IDEA创建方法时快速添加注释
  4. LeetCode 2 Keys Keyboard
  5. DefaultSingletonBeanRegistry 的registerDependentBean()方法对属性注入
  6. C语言数组查找(线性查找 折半查找)
  7. 使用LazZiya.ExpressLocalization开发多语言ASP.NET Core 2.x项目
  8. android里build报错怎么办,Android Studio 当build时候出错解决办法
  9. SQL Server 公用表表达式(CTE)
  10. 组织结构流程图模板分享
  11. java投票小程序_一个实现不记名投票的小程序
  12. 测试人收入情况大曝光,你的收入在什么水平
  13. 【七天实战微信小程序】任务清单
  14. School:1靶机
  15. python 构造函数里的同名变量_Python22个构造函数法-助力数据挖掘与分析
  16. 我的Photoshop大师之路(五)
  17. 抖音取图小程序,同款抖音壁纸,表情包小程序搭建
  18. 认识Lambda表达式
  19. 如何提升权限运行远程桌面客户端?
  20. esp32-C3学习笔记(1)微信配网

热门文章

  1. MyEclipse for Windows 关于 java、jsp、xml、js、html 等文件的注释快捷键及注释格式介绍
  2. linux内核cpu负载计算,CPU 负载 — The Linux Kernel documentation
  3. 将一个文件夹的文件复制到另一个文件夹
  4. matlab 返回变量类型的命令,MATLAB主要命令汇总
  5. 取得二进制最右面为1的数
  6. 华为配备鸿蒙系统的手机,华为P50/新平板双双来袭!全球首发鸿蒙系统:配置都非常强悍...
  7. 机智云代码移植_IoT开发者 | 基于STM32F103的机智云宠物屋外加4路继电器开源教程...
  8. concat合并的数组会有顺序么_JS 数组操作 记录 笔记
  9. yili邮箱服务器配置,手把手教 个人SMTP服务器的配置 -电脑资料
  10. linux内核编译如何选择cpu类型,Ubuntu内核编译和CPU Hot-Plug特性配置全过程及遇到问题记录...