1. 程式人生 > >[JZOJ 5852] [NOIP2018提高組模擬9.6] 相交 解題報告 (倍增+LCA)

[JZOJ 5852] [NOIP2018提高組模擬9.6] 相交 解題報告 (倍增+LCA)

題目連結:

http://172.16.0.132/senior/#main/show/5852

題目:

題目大意:

多組詢問,每次詢問樹上兩條鏈是否相交

題解:

兩條鏈相交併且僅當某一條鏈的兩個端點的LCA在另一個端點上

對於每次詢問,我們分別處理出兩條鏈端點的LCA,通過倍增判斷是否存在一條鏈的LCA在另一條鏈上

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;

const int
N=1e5+15; int n,tot; int h[N],fa[N][20],dep[N]; struct E{ int to,nxt; }e[N<<1]; inline int read(){ char ch=getchar();int s=0,f=1; while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*f; } void link(int u,int v){e[++tot]=(E){v,h[u]};h[u]=tot;} void dfs(int x,int pre){ for (int i=1;i<20;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for (int i=h[x],y;i;i=e[i].nxt){ if ((y=e[i].to)==pre) continue; fa[y][0]=x;dep[y]=dep[x]+1; dfs(y,x); } }
int lca(int x,int y){ if (dep[x]<dep[y]) swap(x,y); for (int i=19;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if (x==y) return x; for (int i=19;i>=0;i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } bool chk(int a,int b,int La,int Lb){ if (dep[Lb]<dep[La]) return 0; if (dep[a]>=dep[Lb]){ for (int i=19;i>=0;i--) if (dep[fa[a][i]]>=dep[Lb]&&dep[fa[a][i]]>=dep[La]) a=fa[a][i]; if (a==Lb) return 1; } if (dep[b]>=dep[Lb]){ for (int i=19;i>=0;i--) if (dep[fa[b][i]]>=dep[Lb]&&dep[fa[b][i]]>=dep[La]) b=fa[b][i]; if (b==Lb) return 1; } return 0; } int main(){ freopen("inter.in","r",stdin); freopen("inter.out","w",stdout); n=read(); for (int i=1,u,v;i<n;i++){ u=read();v=read(); link(u,v);link(v,u); } dep[1]=1;dfs(1,0); int q=read(); while (q--){ int a=read(),b=read(),c=read(),d=read(); int lab=lca(a,b),lcd=lca(c,d); //printf("%d %d\n",lab,lcd); if (chk(a,b,lab,lcd)||chk(c,d,lcd,lab)) puts("YES"); else puts("NO"); } return 0; }