洛谷3379

lca问题

1.树链剖分

#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn 500001
using namespace std;
int n,m,s,cnt,head[maxn],to[maxn<<1],nex[maxn<<1];
int fa[maxn],dep[maxn],id[maxn],a[maxn],top[maxn],siz[maxn],son[maxn];

inline void read(int &x){
    char ch=getchar();x=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
}

void addedge(int u,int v){
    to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;
}

void dfs1(int x,int f){
    dep[x]=dep[f]+1;fa[x]=f;siz[x]=1;
    int maxson=-1;
    for(int i=head[x];i;i=nex[i]){
        int v=to[i];
        if(v==f)continue;
        dfs1(v,x);
        siz[x]+=siz[v];
        if(siz[v]>maxson){son[x]=v;maxson=siz[v];}
    }
}

inline void dfs2(int x,int topf){
    id[x]=++cnt;
    a[cnt]=x;
    top[x]=topf;
    if(!son[x])return;
    dfs2(son[x],topf);
    for(int i=head[x];i;i=nex[i]){
        int y=to[i];
        if(y==fa[x]||y==son[x])continue;
        dfs2(y,y);
    }
}
int query(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);//尤其要注意这里是dep[top[x]]<dep[top[y]],而非dep[x]<dep[y]
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}

int main(){
    read(n);read(m);read(s);
    for(int i=1;i<n;i++){
        int u,v;read(u);read(v);addedge(u,v);addedge(v,u);
    }
    cnt=0;
    dfs1(s,s);dfs2(s,s);
    for(int i=1;i<=m;i++){
        int u,v;read(u);read(v);printf("%d\n",query(u,v));
    }
}

2.tarjan算法

遍历一棵树,不断更新当前节点子节点的父亲。。。具体可看代码,不难

#include<cstdio>
#include<cctype>
#include<vector>
#define maxn 500002
using namespace std;
int n,m,s,cnt,ans[maxn],fa[maxn],h[maxn],head[maxn],to[maxn<<1],nex[maxn<<1];
struct data{int v,id,ans,nex;}q[maxn<<1];
bool vis[maxn];

inline void read(int &x){
    char ch=getchar();x=0;
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
}

void addedge(int u,int v){
    to[++cnt]=v;nex[cnt]=head[u];head[u]=cnt;
}

void add(int u,int v,int id){
    q[++cnt].v=v;q[cnt].id=id;q[cnt].nex=h[u];h[u]=cnt;
}

int findfa(int x){
    if(fa[x]==x)return x;return fa[x]=findfa(fa[x]);
}

void unio(int x,int y){
    int fx=findfa(x),fy=findfa(y);
    fa[fx]=fy;
}

void lca(int now,int fa){
    for(int i=head[now];i;i=nex[i]){
        if(to[i]==fa)continue;
        lca(to[i],now);
        unio(to[i],now);
    }
    vis[now]=1;
    for(int i=h[now];i;i=q[i].nex){
        if(vis[q[i].v])
        ans[q[i].id]=findfa(q[i].v);
    }
}

int main(){
    read(n);read(m);read(s);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<n;i++){
        int u,v;
        read(u);read(v);
        addedge(u,v);addedge(v,u);
    }
    cnt=0;
    for(int i=1;i<=m;i++){
        int u,v;
        read(u);read(v);
        add(u,v,i);add(v,u,i);
    }
    lca(s,0);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
}

3.dfs+倍增

#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn 500005
using namespace std;
int n,m,s,head[maxn],ln[500005],st[maxn][22],dep[maxn];
struct data{int v,nxt;}edge[maxn*2];

inline int read(){
	char ch=getchar();int k=0;
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch)){k=(k<<1)+(k<<3)+ch-'0';ch=getchar();}
	return k;
}

void dfs(int now,int fa){
	dep[now]=dep[fa]+1;
	st[now][0]=fa;
	for(int i=1;(1<<i)<=dep[now];i++)st[now][i]=st[st[now][i-1]][i-1];
	for(int i=head[now];i;i=edge[i].nxt)if(edge[i].v!=fa)dfs(edge[i].v,now);
}

int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y])x=st[x][ln[dep[x]-dep[y]]-1];
	if(x==y)return x;
	for(int j=ln[dep[x]]-1;j>=0;j--)//
	   if(st[x][j]!=st[y][j]) x=st[x][j],y=st[y][j];
	   return st[x][0];
}

int main(){
	n=read();m=read();s=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		edge[i*2-1].v=v;edge[i*2-1].nxt=head[u];head[u]=i*2-1;
		edge[i*2].v=u;edge[i*2].nxt=head[v];head[v]=i*2;
	}
	dfs(s,0);
	for(int i=1;i<=n;i++)ln[i]=ln[i-1]+((1<<ln[i-1])==i);//可以直接公式求,懒得改了
	for(int i=1;i<=m;i++){
		int x=read(),y=read();
		printf("%d\n",lca(x,y));
	}
	return 0;
}

原文地址:https://www.cnblogs.com/MikuKnight/p/8833791.html