这道题思路比较有意思,第一次做完全没想到点子上。。。


看到题目第一反应是一道最短路裸题,但是数据范围1e5说明完全不可能。

这个时候可以观察到题目给出了一个很有意思的条件,就是说边最多比点多20。

这有什么用呢?

那么我们大胆猜想,可否将整个图划分为21条边(连接最多42个点)和一颗树?(极限情况)

如果这样的话,对于任意的两个节点uv,它们之间的最短路只有两种情况:

  1. 这两个点都在树上。所以说最短路必然是u->lca(u,v)->v。

  2. 不是上面那种情况。这个时候肯定会有连到外面那21个边。我们暴力枚举一下就可以了。

到这里思路就完全出来了,我们先把不属于树的点挑出来,对每一个都跑一下最短路。

然后对于每一组询问判断一下属于哪一种情况就可以了。


AC代码如下:

37657ms 67712kb

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
namespace StandardIO{
template<typename T>inline void read(T &x){
x=0;T f=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
x*=f;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>=10)write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve{
#define int long long
const int N=100100;
const int INF=2147483647;
int n,m,p;
int cnt;
int head[N];
struct node{
int to,val,next;
}edge[N<<1];
template<typename T>inline void add(T a,T b,T c){
edge[++cnt].to=b,edge[cnt].val=c,edge[cnt].next=head[a],head[a]=cnt;
}
struct qnode{
int key,val;
bool operator < (qnode x)const{
return val>x.val;
}
};
int top;
int vis[N],fa[N][23],dist[N],dep[N],q[N];
int dis[50][N];
inline void dfs(int now,int father){
vis[now]=1,fa[now][0]=father;
for(register int i=head[now];i;i=edge[i].next){
int to=edge[i].to;
if(to==father)continue;
if(vis[to])q[++top]=now,q[++top]=to;
else{
dep[to]=dep[now]+1,dist[to]=dist[now]+edge[i].val;
dfs(to,now);
}
}
}
template<typename T>inline T lca(T x,T y){
if(dep[x]<dep[y])swap(x,y);
for(register int i=19;i>=0;--i){
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
}
if(x==y)return x;
for(register int i=19;i>=0;--i){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i],y=fa[y][i];
}
}
return fa[x][0];
}
inline void dijkstra(int now){
memset(dis[now],63,sizeof(dis[now]));
memset(vis,0,sizeof(vis));
priority_queue<qnode>Q;
dis[now][q[now]]=0;
Q.push((qnode){q[now],0});
while(!Q.empty()){
int tmp=Q.top().key;Q.pop();
if(vis[tmp])continue;
vis[tmp]=1;
for(register int i=head[tmp];i;i=edge[i].next){
int to=edge[i].to;
if(!vis[to]&&dis[now][tmp]+edge[i].val<dis[now][to]){
dis[now][to]=dis[now][tmp]+edge[i].val;
Q.push((qnode){to,dis[now][to]});
}
}
}
}
inline void solve(){
read(n),read(m);
for(register int i=1;i<=m;++i){
int a,b,c;
read(a),read(b),read(c);
add(a,b,c),add(b,a,c);
}
dep[1]=1,dfs(1,0);
for(register int j=1;j<=19;++j){
for(register int i=1;i<=n;++i){
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
sort(q+1,q+top+1);top=unique(q+1,q+top+1)-q-1;
for(register int i=1;i<=top;++i)dijkstra(i);
read(p);
while(p--){
int x,y;
read(x),read(y);
int ans=dist[x]+dist[y]-2*dist[lca(x,y)];
for(register int i=1;i<=top;++i)ans=min(ans,dis[i][x]+dis[i][y]);
write(ans),putchar('\n');
}
}
}
using namespace Solve;
#undef int
int main(){
solve();
}

题解 CF1051F 【The Shortest Statement】的更多相关文章

  1. 【题解】Luogu CF1051F The Shortest Statement

    原题传送门:CF1051F The Shortest Statement 题目大意,给你一个稀疏图,q次查询,查询两点之间距离 边数减点小于等于20 这不是弱智题吗,23forever dalao又开 ...

  2. CF1051F The Shortest Statement 题解

    题目 You are given a weighed undirected connected graph, consisting of n vertices and m edges. You sho ...

  3. cf1051F. The Shortest Statement(最短路/dfs树)

    You are given a weighed undirected connected graph, consisting of nn vertices and mm edges. You shou ...

  4. [CF1051F]The Shortest Statement

    题目大意:给定一张$n$个点$m$条有权边的无向联通图,$q$次询问两点间的最短路 $n\le100000$,$m\le100000$,$1\le100000$,$m$-$n\le20$. 首先看到$ ...

  5. [CF1051F]The Shortest Statement (LCA+最短路)(给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路)

    题目:给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路 n≤100000,m≤100000,m-n≤20. 首先看到m-n≤20这条限制,我们可以想到是围绕这个20来做这道题. 即如果我们 ...

  6. cf1051F. The Shortest Statement(最短路)

    题意 题目链接 题意:给出一张无向图,每次询问两点之间的最短路,满足$m - n <= 20$ $n, m, q \leqslant 10^5$ Sol 非常好的一道题. 首先建出一个dfs树. ...

  7. CF1051F The Shortest Statement Dijkstra + 性质分析

    动态询问连通图任意两点间最短路,单次询问. 显然,肯定有一些巧妙地性质(不然你就发明了新的最短路算法了233)有一点很奇怪:边数最多只比点数多 $20$ 个,那么就可以将这个图看作是一个生成树,上面连 ...

  8. Codeforces 1051E Vasya and Big Integers&1051F The Shortest Statement

    1051E. Vasya and Big Integers 题意 给出三个大整数\(a,l,r\),定义\(a\)的一种合法的拆分为把\(a\)表示成若干个字符串首位相连,且每个字符串的大小在\(l, ...

  9. [CF1051F]The Shortest Statement_堆优化dij_最短路树_倍增lca

    The Shortest Statement 题目链接:https://codeforces.com/contest/1051/problem/F 数据范围:略. 题解: 关于这个题,有一个重要的性质 ...

  10. codeforces 1051F The Shortest Statement

    题目链接:codeforces 1051F The Shortest Statement 题意:\(q\)组询问,求任意两点之间的最短路,图满足\(m-n\leq 20\) 分析:一开始看这道题:fl ...

随机推荐

  1. OOP 面向对象 七大原则 (二)

    OOP 面向对象   七大原则 (二) 上一篇写到了前四个原则,这一篇继续~~ 接口隔离:客户端不应该依赖它不需要的接口:一个类对另一个类的依赖应该建立在最小的接口上. 又是一句大白话~就是说接口尽量 ...

  2. Java基础学习总结(35)——Java正则表达式详解

    在Sun的Java JDK 1.40版本中,Java自带了支持正则表达式的包,本文就抛砖引玉地介绍了如何使用java.util.regex包. 可粗略估计一下,除了偶尔用Linux的外,其他Linu  ...

  3. <url-pattern>/</url-pattern> 拦截请求

    一.springmvc 前端控制器 <!-- springmvc的前端控制器 --> <servlet> <servlet-name>fw-sso-web</ ...

  4. I - Agri-Net

    I - Agri-Net poj 1258 注意:多组数据输入. #include<cstdio> #include<cstring> #include<iostream ...

  5. java连接数据库核心代码

    一.oracle String driver = "oracle.jdbc.driver.OracleDriver"; String url = "jdbc:Oracle ...

  6. poi判断一行是隐藏的getZeroHeight()

    poi判断一行是隐藏的 getZeroHeight() boolean isZeroHeight = row.getZeroHeight(); if(isZeroHeight){ // 如果为隐藏行就 ...

  7. http协议区分头信息和正文

    http协议中的头信息和正文是採用空行分开,什么是空行呢?简单来说,就是\r\n\r\n. 所以将server返回的数据用\r\n\r\n分开后的结果,一个是头信息.一个是正文信息. C#的代码例如以 ...

  8. [HTML 5] aria-hidden

    You want to use aria-hidden to prevent screen reader to access some content should be hidden from us ...

  9. 路由器一键桥接Android实现

    開始之前,首先说一下什么叫一键桥接,所谓一键桥接,就是点击一下.就能够对所连接的路由器进行网络中继设置.以实现路由器能够通过已有的无线路由器进行网络訪问. 那么实现这个功能有几种方法呢?能够说有非常多 ...

  10. Apache + Tomcat 负载均衡 session复制

    转自:http://blog.csdn.net/cssmhyl/article/details/8455400 http://snowolf.iteye.com/blog/743611 Apache  ...