LCA。。。
樹鏈剖分
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int N=5e5+10;int h[N],e[2*N],ne[2*N],idx=0; void add(int u,int v){e[idx]=v,ne[idx]=h[u],h[u]=idx++;return;}int siz[N],de[N],son[N],top[N],fa[N],id[N],num; void dfs1(int u,int f) //一次dfs求出深度,父親,重兒子; {de[u]=de[f]+1; fa[u]=f; siz[u]=1; //包括自己 可能是更進一步修改整棵子樹的時候好做吧,現在不知道; for(int i=h[u];~i;i=ne[i]){int t=e[i];if(t==f)continue; dfs1(t,u);siz[u]+=siz[t];if(siz[son[u]]<siz[t])son[u]=t; //如果是葉子節點進不來這層,son【u】=0; }return ; } void dfs2(int u,int f) //求出鏈頭,輕鏈的鏈頭是自己,重鏈的鏈頭是重鏈最上面的元素; { top[u]=f; //f是u的鏈頭 if(!son[u])return ;//是葉子節點返回 dfs2結束條件,不加的話 dfs2(son[u],f)就過深,一般不加,因為dfs再for循環里面; dfs2(son[u],f); //重鏈的鏈頭是f; for(int i=h[u];~i;i=ne[i]){int v=e[i];if(v==fa[u]||v==son[u])continue; //不可以寫成v==f,因為輕鏈的鏈頭是他自己; dfs2(v,v); //輕鏈的鏈頭是他自己; } } int LCA(int x,int y) {while(top[x]!=top[y])//當不在一條鏈上; {if(de[top[x]]<de[top[y]])swap(x,y);//鏈頭較深的先上 ; x=fa[top[x]];//到到這條鏈的下一條鏈的鏈尾; }return de[x]<de[y]?x:y; } int main() {memset(h,-1,sizeof h);//這句如果初始化idx=1&&只用建一個圖,那么不用初始化h了; int n,m,s;scanf("%d%d%d",&n,&m,&s);for(int i=1,u,v;i<n;i++){scanf("%d%d",&u,&v);add(u,v);add(v,u);} dfs1(s,0);dfs2(s,s);while(m--){int a,b;scanf("%d%d",&a,&b);printf("%d\n",LCA(a,b));}return 0; }倍增
#include<cstdio> #include<iostream> #include<cstring> #include<vector> using namespace std; const int N=5e5+10; int fa[N][31],deep[N]; vector<int>v[N]; int n,m,s,a,b,c,ans=0;void dfs(int root,int fno) {fa[root][0]=fno;deep[root]=deep[fno]+1;for(int i=1;i<31;i++)fa[root][i]=fa[fa[root][i-1]][i-1];int sz=v[root].size();for(int i=0;i<sz;i++){int t=v[root][i]; if(t==fno)continue;dfs(t,root);} } int lca(int x,int y) {if(deep[x]>deep[y])swap(x,y);int sz=deep[y]-deep[x]; for(int i=0;sz;i++,sz>>=1)//先走到同一高度,那么再走相同的步數就到lca的前一個點; if(sz&1)y=fa[y][i];if(x==y)return x; //特判; for(int i=30;i>=0;i--) //為啥要走到零呢?。。難道是走到lca的前一個點;??? if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; //lca的前一個點的下一個點是lca(當是廢話吧) }int main() {scanf("%d%d%d",&n,&m,&s);for(int i=1;i<=n;i++)v[i].clear();for(int i=1;i<n;i++){scanf("%d%d",&a,&b);v[a].push_back(b),v[b].push_back(a);}dfs(s,0);for(int i=0;i<m;i++){scanf("%d%d",&a,&b);printf("%d\n",lca(a,b));}return 0; }好像第二個代碼好看。。
總結
- 上一篇: A - Junk-Mail Filter
- 下一篇: HEVC编码结构简要总结