题意:给你一个含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+; struct node
{
int u,v,next;
int id,f;
ll w;
}edge[N*]; struct node1
{
int l,r;
ll w;
ll lz;
}tr[N<<]; int tot,head[N];
int n,q;
int anc[N<<][]; int dfn;
int dfns[N*];
int dep[N*];
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=;
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
memset(inde,-,sizeof(inde));
memset(pos,-,sizeof(pos));
clo=; huan=; idd=; dfn=; /// 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=;
edge[tot].next=head[u]; head[u]=tot;
} void dfs1(int u,int fa)
{
if(vis[u]){
uu=fa; vv=u; huan=; return ;
}
vis[u]=;
for(int i=head[u];i!=-;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!=-;i=edge[i].next){
if(edge[i].f) continue; /// 如果是标记的边跳过
int v=edge[i].v;
if(pos[v]==-){
to[edge[i].id]=v; /// 表示这条边指向哪个点?
dfs2(v,deep+);
dfns[dfn]=u; dep[dfn++]=deep;
}
}
R[u]=clo;
} void init_RMQ(int n) /// dfn
{
for(int i=;i<=n;++i) anc[i][]=i;
for(int j=;(<<j)<=n;++j)
for(int i=;i+(<<j)-<=n;++i){
if(dep[anc[i][j-]]<dep[anc[i+(<<(j-))][j-]]) anc[i][j]=anc[i][j-];
else anc[i][j]=anc[i+(<<(j-))][j-];
}
} inline int RMQ(int L,int R)
{
int k=;
while(<<(k+)<=R-L+) ++k;
if(dep[anc[L][k]]<dep[anc[R-(<<k)+][k]]) return anc[L][k];
return anc[R-(<<k)+][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){ /// 查询只有点查询,所以不必更新区间点的sum
ll &lz=tr[i].lz;
tr[lson].lz+=lz; tr[rson].lz+=lz;
tr[lson].w+=lz; tr[rson].w+=lz;
lz=;
}
} void build(int i,int l,int r)
{
tr[i].l=l; tr[i].r=r; tr[i].w=; tr[i].lz=;
if(l==r) return ;
int mid=(l+r)>>;
build(lson,l,mid);
build(rson,mid+,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)>>;
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+,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)>>;
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(,L[u]); sum2=query(,L[v]);
sum3=query(,L[lca]);
return sum1+sum2-sum3*;
} int main()
{
int T;
int u,v,op;
ll w;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&q);
init();
for(int i=;i<=n;i++){
scanf("%d %d %lld",&u,&v,&w);
add(u,v,w,i);
add(v,u,w,i);
ww[i]=w;
} dfs1(,-);/// 第一遍dfs 先找到环中的任意一条边
for(int i=;i<=tot;i++){ /// 给边打上标记
if((edge[i].u==uu&&edge[i].v==vv)||(edge[i].u==vv&&edge[i].v==uu)){
edge[i].f=;
idd=edge[i].id;
cost=edge[i].w;
}
}
dfs2(,);
/*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(,,n); /// 以dfs的遍历出的 L,R 建树 那么接下来就是一个区间更新,单点查询的问题了
for(int i=;i<=n;i++){
if(i==idd) continue;
u=to[i];
update(,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 ;
}

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

  1. 一个Notification 进度条插件(android,NJS实现,直接就可使用)

    参考文章:http://ask.dcloud.net.cn/article/503 源码地址下载 如题,分享一个Notification 进度条插件(android,用js调用原生api实现,直接就可 ...

  2. SQL 拼接多个字段的值&一个字段多条记录的拼接 [轉]

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

  3. 利用OpenCV和MFC对话框建设一个有滑动条控制的播放器--转

    (一)问题的提出: OpenCV有一个很简单的播放视频文件并加载滑动条的程序,但是如何用MFC对话框来创建一个有滑动条控制的播放器呢,网络上四处搜索都没有代码可以参考,下的都是些骗子链接文件,很过分, ...

  4. 使用css3和伪元素制作的一个立体导航条

    使用css3和伪元素制作的一个立体导航条供大家参考,代码如下: <!doctype html> <html lang="en"> <head> ...

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

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

  6. ZOJ 2588 Burning Bridges(求含重边的无向连通图的割边) - from lanshui_Yang

    Burning Bridges Time Limit: 5 Seconds Memory Limit: 32768 KB Ferry Kingdom is a nice little country ...

  7. 【XSY1295】calc n个点n条边无向连通图计数 prufer序列

    题目大意 求\(n\)个点\(n\)条边的无向连通图的个数 \(n\leq 5000\) 题解 显然是一个环上有很多外向树. 首先有一个东西:\(n\)个点选\(k\)个点作为树的根的生成森林个数为: ...

  8. [转]一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程

    一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程 希望此文能给初学多线程编程的朋友带来帮助,也希望牛人多多指出错误. 另外感谢以下链接的作者给予,给我的学习带来了很大帮助 http ...

  9. K - Find them, Catch them POJ - 1703 (带权并查集)

    题目链接: K - Find them, Catch them POJ - 1703 题目大意:警方决定捣毁两大犯罪团伙:龙帮和蛇帮,显然一个帮派至少有一人.该城有N个罪犯,编号从1至N(N<= ...

随机推荐

  1. js 线程和进程的关系

    进程(process)和线程(thread)是操作系统的基本概念 1.计算机的核心是CPU,它承担了所有的计算任务 2.单个CPU一次只能运行一个任务 3.进程它代表CPU所能处理的单个任务.任一时刻 ...

  2. 4.std::string中库函数的使用。

    为了美观,我们把输入和输出设计成如下: #include <iostream> #include <string> int main() { std::string name; ...

  3. Python中常用模块二

    一.hashlib   (加密) hashlib:提供摘要算法的模块 1.正常的md5算法 import hashlib # 提供摘要算法的模块 md5 = hashlib.md5() md5.upd ...

  4. Swing自定义JScrollPane的滚动条设置,重写BasicScrollBarUI方法

    Swing自定义JScrollPane的滚动条设置,重写BasicScrollBarUI方法 摘自:https://blog.csdn.net/qq_31635851/article/details/ ...

  5. 关于instanceof测试遇到的问题

    今天上上课 用 instanceof关键字来判断某个对象是否属于某种数据类型.报错  代码如下 package cn.lijun.demo3; import cn.lijun.demo.Person; ...

  6. [GO]将随机生成的四位数字拆分后放到一个切片里

    package main import ( "math/rand" "time" "fmt" ) func InitData(p *int) ...

  7. What’s the Difference Between a Value Provider and Model Binder?

    ASP.NET MVC 3 introduced the ability to bind an incoming JSON request to an action method parameter, ...

  8. Java 线程的通讯--生产者和消费者

    package 生产者和消费者; //消费者 public class Customer implements Runnable { private Share_resources rescource ...

  9. c# 半角转换为全角 判断是否是全角

    #region 半角转换为全角 /// <summary> /// 半角转换为全角 ////转全角的函数(SBC case) ///任意字符串 ///全角空格为12288,半角空格为32 ...

  10. ntroducing K-Pattern: A Rapid Way to Make CRUD Operations with Entity Framework

    Download Source Introduction Earlier in the last year I made a different approach to work on Entity ...