离线tarjan(dfs)
链式前向星从1开始存,免了赋-1初值,方便异或运算,好处多多。
并查集fa数组的初始化可以写入dfs中顺便执行,少一个大循环。
数组要开大,不然会报WA,可能它在乱搜吧。
//Writer:GhostCai && His Yellow Duck
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN=2000000;
int m,n,root;
inline int read_d(){
int i=0;
char c;
while(c=getchar(),c<'0'||c>'9');
while(c<='9'&&c>='0'){
i=i*10+c-'0';
c=getchar();
}
return i;
}
int fa[MAXN];
int fnd(int x){
return fa[x]==x?x:fa[x]=fnd(fa[x]);
}
inline void cat(int x,int y){
x=fnd(x);y=fnd(y);
fa[y]=x;
}
struct Ques{
int next,id,lca;
}qs[MAXN];
int qhead[MAXN],qcnt=1;
inline void qadd(int x,int y){
qs[++qcnt].id = y;
qs[qcnt].next = qhead[x];
qhead[x]=qcnt;
}
struct Edge{
int next,to;
}e[MAXN];
int head[MAXN],ecnt=1;
inline void add(int x,int y){
e[++ecnt].next = head[x];
e[ecnt].to = y;
head[x]=ecnt;
}
bool vis[MAXN];
int dfs(int id){
vis[fa[id]=id]=1;
// fa[id]=id;
for(int i=head[id];i;i=e[i].next){
int v=e[i].to ;
if(vis[v]) continue;
dfs(v);
cat(id,v);
}
for(int i=qhead[id];i;i=qs[i].next){
int v=qs[i].id ;
if(!vis[v]) continue;
qs[i^1].lca = qs[i].lca = fnd(v);
// if(i%2) qs[i+1].lca = qs[i].lca ;
// else qs[i-1].lca = qs[i].lca ;
}
}
int main(){
int x,y;
// cin>>n>>m>>root;
scanf("%d%d%d",&n,&m,&root);
// for(int i=1;i<=n;i++) fa[i]=i;
// memset(head,-1,sizeof(head));
// memset(qhead,-1,sizeof(qhead));
for(int i=1;i<=n-1;i++){
// cin>>x>>y;
// x=read_d();
// y=read_d();
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=m;i++){
// cin>>x>>y;
// x=read_d();
// y=read_d();
scanf("%d%d",&x,&y);
qadd(x,y);
qadd(y,x);
}
dfs(root);
for(int i=1;i<=m;i++){
printf("%d
",qs[i<<1].lca);
}
}
在线 倍增求法
洛谷模板题cin会T,偷懒写builtin
//Writer:GhostCai && His Yellow Duck
#include<iostream>
#include<cmath>
using namespace std;
const int MAXN=1000000;
int n,m,root;
int dep[MAXN],f[MAXN][32];
int len;
struct Edge{
int next,to;
}e[MAXN];
int head[MAXN],ecnt=1;
inline void add(int x,int y){
e[++ecnt].to = y;
e[ecnt].next = head[x];
head[x] = ecnt;
}
void dfs(int now,int pre){
dep[now]=dep[pre]+1;
f[now][0]=pre;
for(int i=head[now];i;i=e[i].next){
int v=e[i].to ;
if(v==pre) continue;
dfs(v,now);
}
}
void redouble(){
for(int j=1;(1<<j)<=n;j++){
for(int i=1;i<=n;i++){
if(dep[i]-(1<<j)<0) continue;
f[i][j]=f[f[i][j-1]][j-1];
}
}
}
int query(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
// for(int i=len;i>=0;i--){
// if(dep[x]-(1<<i)<dep[y]) continue;
// x=f[x][i];//
// }
// ======================================
// int d=dep[x]-dep[y];
// while(d){
// x=f[x][(int)log2(d&(-d))];
// d-=d&(-d);
// }
// ======================================
int d=dep[x]-dep[y],k=0;
while(d){
if(d&1) x=f[x][k];
k++;
d>>=1;
}
if(x==y) return x;///////
for(int i=len;i>=0;i--){
if(f[x][i]==f[y][i]) continue;
x=f[x][i]; y=f[y][i];
}
return f[x][0];
}
int main(){
cin.sync_with_stdio(false);
cin.tie(0);
cin>>n>>m>>root;
len=log(n)/log(2);
for(int i=1;i<=n-1;i++){
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
dfs(root,0);
redouble();
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
cout<<query(x,y)<<endl;
}
return 0;
}
树剖,极其好写,还是在线查询,常数小,速度媲美tarjan。
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=500005;
int n,m,st;
inline int rd(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
while(isdigit(c))ret=ret*10+c-'0',c=getchar();
return ret*f;
}
struct Edge{
int next,to,w;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y,int w){
e[++ecnt].to = y;
e[ecnt].w = w;
e[ecnt].next = head[x];
head[x] = ecnt;
}
int fa[MAXN],dep[MAXN],siz[MAXN],hch[MAXN];
void dfs1(int cur,int pre){
fa[cur]=pre;dep[cur]=dep[pre]+1;siz[cur]=1;
int mx=-1;
for(int i=head[cur];i;i=e[i].next){
int v=e[i].to;
if(v==pre) continue;
dfs1(v,cur);
siz[cur]+=siz[v];
if(siz[v]>mx) hch[cur]=v,mx=siz[v];
}
}
int id[MAXN],top[MAXN],cnt;
void dfs2(int cur,int tp){
id[cur]=++cnt;top[cur]=tp;
if(hch[cur]) dfs2(hch[cur],tp);
for(int i=head[cur];i;i=e[i].next){
int v=e[i].to;
if(v==fa[cur]||v==hch[cur]) continue;//
dfs2(v,v);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
dep[top[x]]>=dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
}
return dep[x]<=dep[y]?x:y;
}
int main(){
n=rd();m=rd();st=rd();
int x,y;
for(int i=1;i<=n-1;i++){
x=rd();y=rd();
add(x,y,1);add(y,x,1);
}
dfs1(st,0);
dfs2(st,st);
for(int i=1;i<=m;i++){
x=rd();y=rd();
printf("%d
",lca(x,y));
}
return 0;
}