数据一加高,普及变提高
在每组询问中,求与 v i v_i vi 点的最短路径上的最小权值大于等于 k k k 的点的数量 ,由于同一路径上的较大权值对最小权值不会产生影响,因此考虑采用离线做法,按 k k k 值从大到小遍历每组询问。每次将权值大于等于 k k k 的边加入,同时更新连通块的大小。
需要使用带有路径压缩功能的并查集板子,否则会在不断找祖先的路上喜提 T L E TLE TLE 。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int fa[N],cnt[N],ans[N];
struct Node{
int u,v,r;
bool operator<(const Node&t)const{
return r>t.r;
}
}a[N];
struct ask{
int k,v,id;
bool operator<(const ask&t)const{
return k>t.k;
}
}b[N];
//int find(int x){
// if(fa[x]==x)
// return x;
// else
// return find(fa[x]);
//}
int find(int x){//路径压缩 否则会t
if(fa[x]!=x)
fa[x]=find(fa[x]);
return fa[x];
}
void add(int x,int y){
x=find(x);
y=find(y);
if(x!=y){
fa[x]=y;
cnt[y]+=cnt[x];
}
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,Q;
cin>>n>>Q;
for(int i=1;i<=n;i++){//初始化
fa[i]=i;
cnt[i]=1;
}
for(int i=1;i<n;i++)
cin>>a[i].u>>a[i].v>>a[i].r;
for(int i=1;i<=Q;i++){
cin>>b[i].k>>b[i].v;
b[i].id=i;
}
sort(a+1,a+n+1);
sort(b+1,b+Q+1);
int pos=1;
for(int i=1;i<=Q;i++){
while(a[pos].r>=b[i].k){//将所有边权大于当前询问k的加入
add(a[pos].u,a[pos].v);
pos++;
}
ans[b[i].id]=cnt[find(b[i].v)]-1;
}
for(int i=1;i<=Q;i++)
cout<<ans[i]<<endl;
return 0;
}