首先可以 O ( m log n ) O(m\log n) O(mlogn) 按题意把树建出来,显然这是一棵最短路图的生成树。
那么询问 u , v u,v u,v 相当于在树上 ( u , v ) (u,v) (u,v) 路径上找到深度最深的一点 w w w,满足最短路图中刨掉树上路径 ( u , w ) (u,w) (u,w) 上的边后仍有从根到达 v v v 的路径。
考虑处理出 f ( u ) f(u) f(u) 表示 u u u 深度最浅的祖先满足 f ( u ) f(u) f(u) 能通过非树上路径 ( f ( u ) , u ) (f(u),u) (f(u),u) 上的边在最短路图中到达 u u u。
在最短路图上使用拓扑排序从非树边转移即可得到 f ( u ) f(u) f(u)。
那么每次询问 u , v u,v u,v 相当于在树上 ( u , v ) (u,v) (u,v) 路径上找到深度最深的一个点 w w w,满足 d f ( w ) ≤ d u d_{f(w)}\leq d_u df(w)≤du。使用倍增维护 d d d 的最小值即可。
时间复杂度 O ( ( n + m + q ) log n ) O((n+m+q)\log n) O((n+m+q)logn)。
#include<bits/stdc++.h>
#define LN 17
#define N 100010
#define M 200010
#define ll long long
#define INF 0x7fffffff
using namespace std;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int node;
int n,m,s,ty;
namespace Tree
{
int cnt,head[N],to[N],nxt[N];
int d[N],fa[N][LN];
int minn[N][LN];
void adde(int u,int v)
{
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
void dfs(int u)
{
for(int i=1;i<=16;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
fa[v][0]=u,d[v]=d[u]+1;
dfs(v);
}
}
void init()
{
d[s]=1;
dfs(s);
for(int i=0;i<=16;i++) minn[0][i]=INF;
}
void initf(int u,int val)
{
minn[u][0]=val;
for(int i=1;i<=16;i++)
minn[u][i]=min(minn[u][i-1],minn[fa[u][i-1]][i-1]);
}
int getlca(int a,int b)
{
if(d[a]<d[b]) swap(a,b);
for(int i=16;i>=0;i--)
if(d[fa[a][i]]>=d[b])
a=fa[a][i];
if(a==b) return a;
for(int i=16;i>=0;i--)
if(fa[a][i]!=fa[b][i])
a=fa[a][i],b=fa[b][i];
return fa[a][0];
}
int getmin(int u,int f)
{
int ans=INF;
for(int i=16;i>=0;i--)
if(d[fa[u][i]]>=d[f])
ans=min(ans,minn[u][i]),u=fa[u][i];
return min(ans,minn[u][0]);
}
int query(int f,int u)
{
for(int i=16;i>=0;i--)
if(d[fa[u][i]]>=d[f]&&minn[u][i]>d[f])
u=fa[u][i];
return d[u]-d[f];
}
}
namespace DAG
{
int cnt,head[N],to[M],nxt[M];
int du[N];
int f[N];
void adde(int u,int v)
{
du[v]++;
to[++cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
queue<int>q;
void main()
{
for(int i=1;i<=n;i++) f[i]=Tree::d[i];
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
Tree::initf(u,f[u]);
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(Tree::fa[v][0]!=u)
{
int lca=Tree::getlca(u,v);
f[v]=min(f[v],Tree::getmin(u,lca));
}
du[v]--;
if(!du[v]) q.push(v);
}
}
}
}
namespace Graph
{
int p[N];
int cnt,head[N],nxt[M<<1],to[M<<1],w[M<<1];
ll dis[N];
void adde(int u,int v,int wi)
{
to[++cnt]=v;
w[cnt]=wi;
nxt[cnt]=head[u];
head[u]=cnt;
}
namespace Dijkstra
{
struct data
{
int u;ll s;
data(){};
data(int a,ll b){u=a,s=b;}
bool operator < (const data &a) const
{
return s>a.s;
}
};
priority_queue<data>q;
bool vis[N];
void main()
{
memset(dis,127,sizeof(dis));
dis[s]=0;
q.push(data(s,0));
while(!q.empty())
{
data now=q.top();
q.pop();
if(vis[now.u]) continue;
vis[now.u]=1;
for(int i=head[now.u];i;i=nxt[i])
{
int v=to[i];
if(dis[now.u]+w[i]<dis[v])
{
dis[v]=dis[now.u]+w[i];
q.push(data(v,dis[v]));
}
}
}
}
}
struct data
{
int v,p;
data(){};
data(int a,int b){v=a,p=b;}
bool operator < (const data &a) const
{
return p>a.p;
}
};
bool vis[N];
priority_queue<data>q[N];
void dfs(int u)
{
vis[u]=1;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(dis[u]+w[i]==dis[v])
q[u].push(data(v,p[v]));
}
while(!q[u].empty())
{
data now=q[u].top();
q[u].pop();
DAG::adde(u,now.v);
if(vis[now.v]) continue;
Tree::adde(u,now.v);
dfs(now.v);
}
}
void main()
{
for(int i=1;i<=n;i++) p[i]=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
adde(u,v,w),adde(v,u,w);
}
Dijkstra::main();
dfs(s);
}
}
int main()
{
n=read(),m=read(),s=read(),ty=read();
Graph::main();
Tree::init();
DAG::main();
int q=read(),lans=0;
while(q--)
{
int u=read(),v=read();
if(ty) u^=lans,v^=lans;
printf("%d\n",lans=Tree::query(u,v));
}
return 0;
}