题目描述
在 Dato3 的世界里,英雄们通过对量子力学的研究,发现了世界上其实存在
着无数个位面——即是也被称作平行宇宙的存在。
位面有无数多个,每个位面中包含 n 颗行星,由 n−1 个虫洞链接。同一个位
面中的任意两颗行星间有唯一的虫洞路径。
量子力学之父巴拉森指出:“每个位面都看起来差不多。”,揭示了所有位面中
的虫洞都是相同的的道理。也即,如果某个位面中在行星 q1 和 q2 之间有虫洞,那
么任意位面中 q1 和 q2 间都有虫洞。位面从 1 开始编号,一个位面中的行星编号为
1 到 n 。因此使用位面和行星的编号就能唯一确定一颗行星。
艾欧使用它最近获得的至宝”Portal Gun” 建造了 m 个可以双向通行的传送门。
每个传送门用四个整数 p1; u1; p2; u2 描述,代表可以让人们在 u1 位面的 p1 行星和
u2 位面的 p2 行星间移动。通过虫洞或者传送门移动都需要花费 1 单位的时间。
负责星际医疗协助的暗影牧师戴泽希望你能帮忙计算行星间的最短路,共有 q
个询问需要你回答。
2.2 输入格式
输入的第一行包含三个整数 n; m 和 q ,分别代表单个位面中的行星数、传送
门的数量,以及询问的数量。
接下来 n−1 行描述位面中的虫洞,每行包含两个整数,代表一个虫洞所连接
的两个行星。
接下来 m 行描述传送门,每行包含四个整数 p1; u1; p2; u2 。
接下来 q 行描述询问,每行包含四个整数 p1; u1; p2; u2 ,你需要回答从 u1 位
面的 p1 行星到 u2 位面的 p2 行星的最短距离。
4
2.3 输出格式
对于每个询问,输出一行,包含一个整数,代表最短路径的耗时。如果无法到
达,则输出“ impossible”(不含引号)。
2.4 样例输入
3 3 3
1 2
2 3
1 1 1 3
3 1 3 2
1 2 3 3
2 1 2 2
2 1 2 3
1 2 3 2
2.5 样例输出
3 4 2
2.6 数据范围
对于 30% 的数据, 1 ≤ n ≤ 1000; 1 ≤ m ≤ 3000; 1 ≤ u1; u2 ≤ 1000 。
对于另外 20% 的数据,一个位面中的行星形成一条链。
对于 100% 的数据, 1 ≤ n ≤ 300000; 1 ≤ m ≤ 100000; 1 ≤ q ≤ 10; 1 ≤ p1; p2 ≤
n; 1 ≤ u1; u2 ≤ 200000 。
5
保证由虫洞和传送门形成的整张图不含重边或自环。

题解:

弄u1棵树显然是不现实的,于是我们可以改变spfa的方式,直接把每一个位面中的关键点都存起来,然后直接以这些关键点跑spfa

其他的点可以不用管,然后转移之间用树上距离即可 建图可以hash,距离直接树剖lca即可

 #include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#pragma comment(linker, "/STACK:1048576000,1048576000")
using namespace std;
const int N=,M=;
typedef long long ll;
const ll INF=2e15;
int gi(){
int str=;char ch=getchar();
while(ch>'' || ch<'')ch=getchar();
while(ch>='' && ch<='')str=(str<<)+(str<<)+ch-,ch=getchar();
return str;
}
int head[N],num=,ids=,bel[N],id[N];
struct Lin{
int next,to;
}a[N<<];
int Head[N],nm=;
struct hash{
int next,id;ll to;
}b[N<<];
bool vt[N*];
void adds(int x,int y,int id){
ll cnt=(ll)(x*+y);int k=cnt%N;
b[++nm].next=Head[k];
b[nm].to=cnt;
b[nm].id=id;
Head[k]=nm;
}
int find(int x,int y){
ll cnt=(ll)(x*+y);int k=cnt%N;
for(int i=Head[k];i;i=b[i].next){
if(b[i].to==cnt)return b[i].id;
}
return ;
}
void init(int x,int y){
a[++num].next=head[x];
a[num].to=y;
head[x]=num;
}
void addedge(int x,int y){
init(x,y);init(y,x);
}
int n,m,Q;
vector<int>t[N];
vector<int>key[M];
int size[N],top[N],son[N],dep[N],fa[N];
void dfs1(int x){
int u;
size[x]=;
for(int i=,sz=t[x].size();i<sz;i++){
u=t[x][i];
if(dep[u])continue;
dep[u]=dep[x]+;fa[u]=x;
dfs1(u);
size[x]+=size[u];
if(size[u]>size[son[x]])son[x]=u;
}
}
void dfs2(int x,int tp){
top[x]=tp;
int u;
if(son[x])dfs2(son[x],tp);
for(int i=,sz=t[x].size();i<sz;i++){
u=t[x][i];
if(u!=son[x] && u!=fa[x])dfs2(u,u);
}
}
int query(int x,int y){
int tx=dep[x]+dep[y];
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])
swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return tx-(dep[x]<<);
}
int q[N*],mod=N*;int vis[N];ll f[N];
void spfa()
{
int x1=gi(),u1=gi(),y1=gi(),u2=gi(),u,x;
for(int i=;i<=ids;i++)f[i]=INF,vis[i]=false;
int t=,sum=;ll dist;
for(int i=,sz=key[u1].size();i<sz;i++){
u=key[u1][i];
f[u]=query(id[u],x1);
q[++sum]=u;
vis[u]=true;
}
while(t!=sum){
t++;t%=mod;x=q[t];
for(int i=head[x];i;i=a[i].next){
u=a[i].to;
if(f[x]+<f[u]){
f[u]=f[x]+;
if(vt[vis[u]])vt[vis[u]]=false;
if(!vis[u])sum++,sum%=mod,q[sum]=u,vis[u]=sum,vt[sum]=false;
}
}
if(!vt[vis[x]])
for(int i=,sz=key[bel[x]].size();i<sz;i++){
u=key[bel[x]][i];
if(u==x)continue;
dist=query(id[u],id[x]);
if(f[x]+dist<f[u]){
f[u]=f[x]+dist;
if(!vis[u])sum++,sum%=mod,q[sum]=u,vis[u]=sum,vt[sum]=true;
}
}
vis[x]=;
}
ll ans=2e15;
for(int i=,sz=key[u2].size();i<sz;i++){
u=key[u2][i];
dist=query(id[u],y1);
if(f[u]+dist<ans)ans=f[u]+dist;
}
if(u1==u2)ans=min(ans,(ll)query(x1,y1));
if(ans!=2e15)printf("%lld\n",ans);
else printf("impossible\n");
}
int main()
{
freopen("m.in","r",stdin);
freopen("m.out","w",stdout);
n=gi();m=gi();Q=gi();
int x,y;
for(int i=;i<n;i++){
x=gi();y=gi();
t[x].push_back(y);t[y].push_back(x);
}
dep[]=;
dfs1();dfs2(,);
int u1,u2,xx,yy;
for(int i=;i<=m;i++){
x=gi();u1=gi();y=gi();u2=gi();
xx=find(u1,x);yy=find(u2,y);
if(!xx)xx=++ids,key[u1].push_back(ids),bel[ids]=u1,id[ids]=x,adds(u1,x,ids);
if(!yy)yy=++ids,key[u2].push_back(ids),bel[ids]=u2,id[ids]=y,adds(u2,y,ids);
addedge(xx,yy);
}
while(Q--)spfa();
return ;
}

暗牧 (m)的更多相关文章

  1. dota玩家与英雄契合度的计算器,python语言scrapy爬虫的使用

    首发:个人博客,更新&纠错&回复 演示地址在这里,代码在这里. 一个dota玩家与英雄契合度的计算器(查看效果),包括两部分代码: 1.python的scrapy爬虫,总体思路是pag ...

随机推荐

  1. vivado License导入方法与资源获取

    前言 以下安装说明基于已经正确安装vivado 笔者操作环境:linux vivado版本:2015.2 vivado License导入方法: 点击菜单栏[Help],选择[Manage Licen ...

  2. DistBlockNet:A Distributed Blockchains-Based Secure SDN Architecture for IOT Network

    现有问题 随着IOT中智能设备多样性和数目的增加,IOT的灵活性,效率,可用性,安全性和可扩展性的问题越来越明显. 实验目标 按照高适应性,可用性,容错性,性能,可靠性,可扩展性和安全性的设计原则,构 ...

  3. 一个轻量级iOS安全框架:SSKeyChain

    摘要 SSKeyChains对苹果安全框架API进行了简单封装,支持对存储在钥匙串中密码.账户进行访问,包括读取.删除和设置.SSKeyChain的作者是大名鼎鼎的SSToolkit的作者samsof ...

  4. 从源码角度看LinkedList一些基本操作(jdk1.7)

    介绍 LinkedList是一个双向链表,就像下图展示那样,每个节点有个指向上个元素和一个指向下个元素的指针. 接下来我会对我们经常使用的方法进行介绍,代码如下 @Test public void t ...

  5. PHP分页初探 一个最简单的PHP分页代码的简单实现

    PHP分页代码在各种程序开发中都是必须要用到的,在网站开发中更是必选的一项. 要想写出分页代码,首先你要理解SQL查询语句:select * from goods limit 2,7.PHP分页代码核 ...

  6. 使用C#开发Android应用之WebApp

    近段时间了解了一下VS2017开发安卓应用的一些技术,特地把C#开发WebApp的一些过程记录下来, 欢迎大家一起指教.讨论,废话少说,是时候开始表演真正的技术了.. 1.新建空白Android应用 ...

  7. [phpvia/via] PHP多进程服务器模型中的惊群

    [ 概述 ] 典型的多进程服务器模型是这样的,主进程绑定ip,监听port,fork几个子进程,子进程安装信号处理器,随后轮询资源描述符检查是否可读可写: 子进程的轮询又涉及到 IO复用,accept ...

  8. Docker学习笔记 - Docker的仓库

  9. hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(4)SPARK 安装

    hadoop2.7.3+spark2.1.0+scala2.12.1环境搭建(4)SPARK 安装 一.依赖文件安装 1.1 JDK 参见博文:http://www.cnblogs.com/liugh ...

  10. Spring入门(3-1)Spring的标签命名空间

    1.标签命名空间声明: 2.标签命名空间使用 标签默认的命名空间是 security:,可以不用带 security:,直接写标签,如: <http  <authentication-ma ...