洛谷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; }