P11801 【MX-X9-T5】『GROI-R3』Star Trip sol
我永远喜欢 Neri 酱!
先考虑最优策略是什么:假设我们从点
在所有这样的操作都做完后,与连通块相邻的所有点编号都大于
这个过程看起来很能倍增,考虑求出以每个点为起点,其对应的连通块能到达的权值最大的点。我们按照编号从小到大的顺序求解,对当前点
现在对于一个询问,我们就可以倍增得到
总复杂度
code :
#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define int long long
#define pb push_back
#define il inline
il 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^48);
ch=getchar();
}
return x*f;
}
int T=1,n,m,q,k;
int s[N];
char c[N];
vector<int> v[N];
int w[N],ww[N];
int to[21][N];
struct node{
int x,y,z;
}e[N];
il bool cmp(const node &a,const node &b){
return a.z<b.z;
}
int tot,f[N];
il int fd(int x){
if(x==f[x])return x;
return f[x]=fd(f[x]);
}
int val[N];
vector<int> V[N];
il void link(int x,int y,int z){
int a=fd(x),b=fd(y);
if(a==b)return ;
val[++tot]=z;
f[a]=f[b]=tot;
V[tot].pb(a),V[tot].pb(b);
}
int fa[21][N],dep[N];
il void dfs(int x){
for(int i=1;i<=20;i++)
fa[i][x]=fa[i-1][fa[i-1][x]];
for(auto y:V[x]){
fa[0][y]=x;
dep[y]=dep[x]+1;
dfs(y);
}
}
il int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[fa[i][x]]>=dep[y])
x=fa[i][x];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(fa[i][x]!=fa[i][y])
x=fa[i][x],y=fa[i][y];
return fa[0][x];
}
il void solve(){
tot=n=read();m=read();q=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
e[i].x=x,e[i].y=y,e[i].z=max(x,y);
v[x].pb(y),v[y].pb(x);
}
sort(e+1,e+1+m,cmp);
for(int i=1;i<=n*2;i++)f[i]=i;
for(int i=1;i<=m;i++){
link(e[i].x,e[i].y,e[i].z);
}
dfs(tot);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++)w[i]=i;
for(int x=1;x<=n;x++){
for(auto y:v[x]){
if(y<x)w[x]=max(w[x],ww[fd(y)]);
else w[x]=max(w[x],y);
}
ww[x]=w[x];
for(auto y:v[x]){
if(y<x){
int a=fd(x),b=fd(y);
if(a==b)continue;
ww[b]=max(ww[b],ww[a]);
f[a]=b;
}
}
}
for(int i=1;i<=n;i++)to[0][i]=w[i];
for(int k=1;k<=20;k++)for(int i=1;i<=n;i++)to[k][i]=to[k-1][to[k-1][i]];
while(q--){
int x=read(),y=read();
int aaa=val[lca(x,y)];
if(x>=aaa){
puts("1");
continue;
}
int sum=0;
for(int k=20;k>=0;k--)
if(to[k][x]<aaa){
sum+=(1<<k);
x=to[k][x];
}
printf("%lld\n",sum+2);
}
}
signed main(){
T=1;
while(T--)solve();
return 0;
}