SP3978 DISQUERY - Distance Query
题目链接
SP3978 DISQUERY - Distance Query
题目描述
给有 \(n\) 个节点的树, 树上边有边权. 再给定 \(q\) 组询问, 每次询问两个点路径上的最小值和最大值.
本题中的 \(n\) (节点个数) 和 \(q\) (询问个数) 范围都是 \(1 \sim 100000\).
解题思路
tarjan
单单考虑最大值,即求树上两点之间的最大权值,当前遍历到 \(i\) 点,设置数组 \(e[j]\) 表示 \(j\) 到 \(i\) 和 \(j\) 的 \(lca\) 的最大权值,采用并查集向上标记法,标记已访问的当前节点,将 \(lca\) 相等的两节点存储起来,等到下次遍历到 \(lca\) 即当前节点回溯时,上面的节点都是根节点,此时路径还未压缩,此时压缩路径,同时更新下面的两个节点到 \(lca\) 的最大权值。另外,注意初始化当前节点的最大值,由于是边权,每次并查集查询到根节点时会直接返回,同时没有查询到根节点时要用到父节点的信息来更新本身的信息,如果该父节点正好为根节点的话,该父节点的信息显然是没用的,因为边的信息存储在儿子节点上,所以一开始需要初始化
- 时间复杂度:\(O(n+q)\)
代码
// Problem: SP3978 DISQUERY - Distance Query
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/SP3978
// Memory Limit: 1500 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e5+5;
int n,q,fa[N];
vector<PII> adj[N],query[N];
PII res[N],e[N],a[N];
vector<int> ids[N];
bool vis[N];
int find(int x)
{
if(x==fa[x])return x;
int t=find(fa[x]);
e[x].fi=min(e[x].fi,e[fa[x]].fi);
e[x].se=max(e[x].se,e[fa[x]].se);
return fa[x]=t;
}
void add_query(int u,int v,int id)
{
query[u].pb({v,id});
query[v].pb({u,id});
}
void tarjan(int u,int father)
{
e[u].fi=0x3f3f3f3f,e[u].se=0;
for(auto t:adj[u])
{
int v=t.fi,w=t.se;
if(v==father)continue;
tarjan(v,u);
e[v].fi=e[v].se=w;
fa[v]=u;
}
vis[u]=true;
for(auto t:query[u])
{
int v=t.fi,id=t.se;
if(vis[v])ids[find(v)].pb(id);
}
for(auto id:ids[u])
{
int u=a[id].fi,v=a[id].se;
find(u),find(v);
res[id].fi=min(e[u].fi,e[v].fi);
res[id].se=max(e[u].se,e[v].se);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
fa[i]=i;
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
adj[x].pb({y,w});
adj[y].pb({x,w});
}
fa[n]=n;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&a[i].fi,&a[i].se);
add_query(a[i].fi,a[i].se,i);
}
tarjan(1,0);
for(int i=1;i<=q;i++)printf("%d %d\n",res[i].fi,res[i].se);
return 0;
}