标签:appdata jin 原创 wcc 循环 ++ 同步 cti otc
//树上倍增LCA 70pnts 复杂度O((n+m)logn) #include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<ctime> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #define N 500010 using namespace std; struct tree{ int next,ver; }g[N<<2]; queue<int> q; int head[N<<2],tot,t,n,m,s;//t树的深度 int d[N<<2],f[N<<1][30];//d[]某结点处树的深度,f[x][i]第x个结点向根节点走2^i步的结点 void add(int x,int y) { g[++tot].ver=y; g[tot].next=head[x],head[x]=tot; } void reset(int x) { memset(d,0,sizeof(d)); q.push(x); d[x]=1; while(q.size()) { int index=q.front();q.pop();//index是相对当前遍历节点的父节点 for(int i=head[index];i;i=g[i].next) { int y=g[i].ver; if(d[y]) continue;//如果已经处理过了就进入下一轮循环 d[y]=d[index]+1;//深度增加 f[y][0]=index;//你爸是我 for(int j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1]; q.push(y); } } } int lca(int x,int y) { if(d[x]<d[y]) swap(x,y);//使得x比y深度大 for(int i=t;i>=0;i--) if(d[f[x][i]]>=d[y]) x=f[x][i];//使得x与y深度相等 if(x==y) return x; for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0];//此时x和y并未更新为它们的LCA,而是刚好在它下面一个结点,于是我们返回这个结点的爸爸 } int main() { scanf("%d%d%d",&n,&m,&s); t=(int)(log(n)/log(2))+1; for(int i=1;i<=n-1;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y);add(y,x); } reset(s); for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); cout<<lca(x,y)<<endl; } return 0; }
//Tarjan O(n+m) #include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<ctime> #include<cstdlib> #include<algorithm> #include<queue> #include<set> #include<map> #define N 500010 using namespace std; struct tree{ int next,ver; }g[N<<2]; queue<int> q; int head[N<<2],tot,t,n,m,s;//t树的深度 int fa[N<<1],v[N],lca[N],ans[N];//d[]某结点处树的深度,f[x][i]第x个结点向根节点走2^i步的结点 vector<int> query[N],query_id[N]; void add(int x,int y) { g[++tot].ver=y; g[tot].next=head[x],head[x]=tot; } void add_query(int x,int y,int id) { query[x].push_back(y),query_id[x].push_back(id); query[y].push_back(x),query_id[y].push_back(id); } int get(int x) { if(fa[x]==x) return x; return fa[x]=get(fa[x]); } void tarjan(int x) { v[x]=1;//标记这个结点被递归到 for(int i=head[x];i;i=g[i].next){//dfs整颗树 int y=g[i].ver; if(v[y]) continue; tarjan(y); fa[y]=x;//将这个结点和它的父节点合并 } for(int i=0;i<query[x].size();i++){//检查关于当前所在结点的询问 int y=query[x][i],id=query_id[x][i];//取出询问 if(v[y]==2){//如果该结点已经回溯 int lca=get(y);//当前x与y的LCA ans[id]=lca; } } v[x]=2;//回溯,标记为2 } int main() { scanf("%d%d%d",&n,&m,&s); t=(int)(log(n)/log(2))+1;//树的深度 for(int i=1;i<=n;i++){//初始化 head[i]=0,fa[i]=i,v[i]=0; query[i].clear(),query_id[i].clear(); } for(int i=1;i<=n-1;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y);add(y,x); } for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); if(x==y) ans[i]=x; else{ add_query(x,y,i);//输入询问 } } tarjan(s); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
标签:appdata jin 原创 wcc 循环 ++ 同步 cti otc
原文地址:https://www.cnblogs.com/DarkValkyrie/p/10990500.html