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;
}
posted @ 2022-04-26 21:38  zyy2001  阅读(61)  评论(0编辑  收藏  举报