LCA:树剖、倍增、Tarjan
-
树剖 - O(logn)(n<=10^6)
-
https://www.cnblogs.com/cangT-Tlan/p/8846408.html
-
把一棵树分成几条链,用数据结构去维护每一条链
-
#include<bits/stdc++.h> #define ll long long #define rll register ll #define M 0x3f3f3f #define For(i,l,r) for(int i=l;i<=r;i++) using namespace std; ll n,m,s,head[M],a[M],x,y,z,tot,k,t; ll fa[M],d[M],top[M],size[M],id[M],ril[M]; struct node1{ ll to,nxt; }e[M<<1]; struct node2{ ll l,r,sum,flag; }tree[M<<1]; inline ll read(){ ll f=1,sum=0; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){sum=(sum<<1)+(sum<<3)+(ch^48);ch=getchar();} return f*sum; } inline void add(ll x,ll y){ e[++tot].to=y; e[tot].nxt=head[x]; head[x]=tot; } inline void dfs1(ll u){//第一遍dfs遍历树,预处理d深度,size此点子节点个数,fa其父节点 d[u]=d[fa[u]]+1; size[u]=1; for(rll i=head[u];i;i=e[i].nxt){ if(e[i].to!=fa[u]){ fa[e[i].to]=u; dfs1(e[i].to); size[u]+=size[e[i].to]; } } } inline void dfs2(ll u){//按照子节点个数多少划分轻重边,保证一个点只在一条链中。一般只用重边,轻边用不到。 ll t=0;//top即为此点所在重边的顶点 if(!top[u]) top[u]=u; for(rll i=head[u];i;i=e[i].nxt){ if(e[i].to!=fa[u]&&size[e[i].to]>t) t=e[i].to; } if(t){ top[t]=top[u]; dfs2(t); } for(rll i=head[u];i;i=e[i].nxt){ if(e[i].to!=fa[u]&&e[i].to!=t) dfs2(e[i].to); } } inline ll lca(ll x,ll y){//当两个点位于同一条重链上即结束操作。否则深度深的点跳到所在重链的上一个点,结束操作时深度浅的点的位置即为所求lca while(top[x]!=top[y]){ if(d[top[x]]<d[top[y]]) swap(x,y); x=fa[top[x]]; } if(d[x]>d[y]) swap(x,y); return x; } int main(){ n=read(),m=read(),s=read(); For(i,1,n-1) {x=read(),y=read(),add(x,y),add(y,x);} dfs1(s),dfs2(s); For(i,1,m){x=read(),y=read(),printf("%lld\n",lca(x,y));} return 0; }
-
题目:
-
仓鼠找sugar