Z2219. [ABC235E] MST + 1
先写一发LCA
#include<bits/stdc++.h> using namespace std; int n,q,x,y,dep[500005],jump[500005][22]; vector<int>d[500005]; void findep(int p,int f,int dp) { dep[p]=dp; //点p的深度为dp for(int i=0;i<=int(d[p].size()-1);i++) if(d[p][i]!=f) { int pn=d[p][i]; jump[pn][0]=p; //pn向上跳2^0即1步的时候,就是它的父亲点 findep(pn,p,dp+1); } return ; } int lca(int ix,int iy) { if(dep[ix]<dep[iy]) //规定ix是深度较大的点 swap(ix,iy); for(int i=20;i>=0;i--) //一定是倒过来循环 if(dep[jump[ix][i]]>=dep[iy]) //如果一直跳在iy的下方,才能跳 ix=jump[ix][i]; if(ix==iy) //如果重合,就出结果了 return ix; for(int i=20;i>=0;i--) //又是倒过来循环 if(jump[ix][i]!=jump[iy][i]) //所跳的点,必须是两个不同的点 { ix=jump[ix][i]; iy=jump[iy][i]; } return jump[ix][0]; //ix的父亲点即是结果 } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n-1;i++) { scanf("%d%d",&x,&y); d[x].push_back(y); d[y].push_back(x); } findep(1,0,1); for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) jump[j][i]=jump[jump[j][i-1]][i-1]; for(int i=1;i<=q;i++) { scanf("%d%d",&x,&y); printf("%d\n",lca(x,y)); } return 0; }
再改一下,求出树上任两点之间的最长边
#include<bits/stdc++.h> using namespace std; const int N=2e5+10,M=N*2; int n,m,q; struct edge { int u,v,w; bool operator<(const edge &x) const { return w<x.w; } }ed[N]; int fa[N]; int h[N],e[M],ne[M],w[M],tot; int f[N][22],g[N][22],dep[N]; int find(int x) { if(fa[x]==x) return x; return fa[x]=find(fa[x]); } void add(int a,int b,int c) { e[++tot]=b;w[tot]=c;ne[tot]=h[a];h[a]=tot; } void dfs(int x,int FA,int d) //x表示在哪个点,fa是它父亲点,d是深度 { dep[x]=d; f[x][0]=FA; for(int i=h[x];i;i=ne[i]) { int j=e[i]; if(j==FA) continue; g[j][0]=w[i]; dfs(j,x,d+1); } } int get_lca(int a,int b) { if(dep[a]<dep[b]) swap(a,b); //规定a是深度较大的 int ans=0; for(int i=20;i>=0;i--) if(dep[f[a][i]]>=dep[b]) { ans=max(ans,g[a][i]); a=f[a][i]; } if(a==b) return ans; for(int i=20;i>=0;i--) if(f[a][i]!=f[b][i]) { ans=max(ans,max(g[a][i],g[b][i])); a=f[a][i]; b=f[b][i]; } return max(ans,max(g[a][0],g[b][0])); } signed main() { scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=m;i++) scanf("%d%d%d",&ed[i].u,&ed[i].v,&ed[i].w); sort(ed+1,ed+1+m); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int a=find(ed[i].u),b=find(ed[i].v); if(a==b) continue; fa[a]=b; add(ed[i].u,ed[i].v,ed[i].w); add(ed[i].v,ed[i].u,ed[i].w); } dfs(1,0,1); for(int i=1;i<=20;i++) for(int j=1;j<=n;j++) { f[j][i]=f[f[j][i-1]][i-1]; g[j][i]=max(g[j][i-1],g[f[j][i-1]][i-1]); } for(int i=1;i<=q;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); int lca=get_lca(a,b); if(lca>c) printf("Yes\n"); else printf("No\n"); } return 0; }
NOIP模板题--货车运输