这是一个在线算法——这是非常重要的一点,求一次的复杂度是logn
总复杂度为mlogn
个人过的,介绍几题1036 商务旅行 codevs
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<cstring> #include<string> #include<vector> const int MAXN=30007; using namespace std; vector<int>to[MAXN];//记录到达的边 int n,deep[30007],a[30007],m,f[MAXN][20]; void init(); void dfs(int x,int dfn,int fa); int lca(int x,int y); void init_f(); int main() { int x,y; scanf("%d",&n); init(); for (int i=1;i<n;i++) { scanf("%d%d",&x,&y); to[x].push_back(y); to[y].push_back(x); } dfs(1,1,-1); init_f(); scanf("%d",&m); a[1]=0; for (int i=2;i<=m+1;i++) scanf("%d",&a[i]); int ans=0; for (int i=1;i<=m;i++) { x=lca(a[i],a[i+1]); ans+=(deep[a[i]]+deep[a[i+1]]-2*deep[x]); } cout<<ans-1<<endl;//应为点比经过的边多一 } void init() { for (int i=1;i<=n;i++) { to[i].clear(); } memset(deep,0,sizeof(deep)); memset(a,0,sizeof(a)); memset(f,-1,sizeof(f)); } void dfs(int x,int dfn,int fa)//dfn记录的是深度,fa是父亲 { deep[x]=dfn; f[x][0]=fa; int xx=to[x].size(); for (int i=0;i<xx;i++) { if (to[x][i]!=fa) dfs(to[x][i],dfn+1,x); } } void init_f()//初始化f的值,以f[x][0]从dfs中求出来更新其他父亲。 { for (int j=1;(1<<j)<=n;j++) for (int i=1;i<=n;i++) if (f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1]; } int lca(int x,int y) { int i; if (deep[x]<deep[y]) swap(x,y);//注意!这个必要的,否则下面影响 for (i=0;(1<<i)<=deep[x];i++); i--; for (int j=i;j>=0;j--) if (deep[x]-(1<<j)>=deep[y]) x=f[x][j];//使其深度相同 if (x==y) return x; for (int j=i;j>=0;j--) { if (f[x][j]!=-1&&f[x][j]!=f[y][j]) { x=f[x][j]; y=f[y][j]; } } return f[x][0]; }
另外一题难度差不多,只是边上多了一个权值,这时只是dfs稍加改进即可
http://codevs.cn/problem/2370/
也是codevs上的题,还可以。
题意也是一眼题
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<cstring> #include<string> #include<vector> const int MAXN=50007; using namespace std; vector<int> to[MAXN],zhi[MAXN]; int n,m,deep[MAXN],f[MAXN][20],dis[MAXN]; void init(); void init_f(); int lca(int a,int b); void dfs(int x,int dfn,int fa,int where); int main() { int x,y,z; init(); scanf("%d",&n); for (int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); to[x].push_back(y); to[y].push_back(x); zhi[x].push_back(z); zhi[y].push_back(z); } dfs(0,1,-1,-1); init_f(); scanf("%d",&m); for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); z=lca(x,y); cout<<dis[x]+dis[y]-2*dis[z]<<endl; } } void init() { for (int i=1;i<=MAXN;i++) { to[i].clear(); zhi[i].clear(); } memset(f,0,sizeof(f)); memset(deep,0,sizeof(deep)); } void dfs(int x,int dfn,int fa,int where) { deep[x]=dfn; if (fa==-1) dis[x]=0; else dis[x]=dis[fa]+zhi[fa][where]; int xx=to[x].size(); for (int i=0;i<xx;i++) { if (to[x][i]==fa) continue; f[to[x][i]][0]=x; dfs(to[x][i],dfn+1,x,i); } } void init_f() { for (int j=1;(1<<j)<=n;j++) for (int i=0;i<n;i++) if (f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1]; } int lca(int a,int b) { if (deep[a]<=deep[b]) swap(a,b); int i; for (i=0;(1<<i)<=deep[a];i++); i--; for (int j=i;j>=0;j--) if (deep[a]-(1<<j)>=deep[b]) a=f[a][j]; if (a==b) return a; for (int j=i;j>=0;j--) { if (f[a][j]!=-1&&f[a][j]!=f[b][j]) { a=f[a][j]; b=f[b][j]; } } return f[a][0]; }
代码不长,倍增实现,在线算法,复杂度O(mlogn)