hdu2586(最近公共祖先-两种方法实现)
这道题题意是,给定一棵树,每条边都有一定的权值,q次询问,每次询问某两点间的距离。这样就可以用LCA来解,首先找到u, v 两点的lca,然后计算一下距离值就可以了。这里的计算方法是,记下根结点到任意一点的距离dis[],这样ans = dis[u] + dis[v] - 2 * dis[lca(v, v)]了,这个表达式还是比较容易理解的。。
离线复杂度:O(n+m)
在线复杂度:O(nlgn+mlgn)
显然离线的算法有优势!!!!!!!!(在线算法的思想很好)
法一(离线法):LCA Tarjan算法--模版:
http://www.cnblogs.com/sbaof/articles/3338961.html
我的修改版(自己的更好!):
//#pragma comment(linker, "/STACK:102400000") #include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define ULL unsigned long long #define LL long long #define pb push_back #define mp make_pair #define inf 0x7fffffff #define eps 1e-7 #define N 40009 #define M 209 using namespace std; int m,n,T,t,x,y; int dist[N],f[N]; int vis[N]; vector<pair<int,int> >g[N]; vector<pair<int,int> >q[N]; int u[M],v[M],fa[M]; int find(int x) { return x==f[x]?x:f[x]==find(f[x]); } void tarjan(int u)//求fa,dist,改f值 { f[u]=u; vis[u]=1; for(int i=0;i<q[u].size();i++) { int v=q[u][i].first; int sub=q[u][i].second; if(vis[v]) { fa[sub]=find(v);//find(v)不是f[v] } } for(int i=0;i<g[u].size();i++) { int v=g[u][i].first; int len=g[u][i].second; if(!vis[v])//非父节点 { dist[v]=dist[u]+len; tarjan(v); f[v]=u;//遍历完其子节点再改 } } } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0; i<=n; i++) { g[i].clear(); q[i].clear(); } memset(vis,0,sizeof(vis)); for(int i=1; i<n; i++) { scanf("%d%d%d",&x,&y,&t); g[x].pb(mp(y,t)); g[y].pb(mp(x,t)); } for(int i=0; i<m; ++i) { scanf("%d%d",&u[i],&v[i]); q[u[i]].pb(mp(v[i],i)); q[v[i]].pb(mp(u[i],i)); } dist[1]=0; tarjan(1); for(int i=0;i<m;i++) printf("%d\n",dist[u[i]]+dist[v[i]]-2*dist[fa[i]]); } return 0; }
法二(在线法):
http://www.cnblogs.com/sbaof/articles/3338967.html
我的修改版:
//#pragma comment(linker, "/STACK:102400000") #include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<cmath> #include<list> #include<queue> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define pb push_back #define mp make_pair #define ULL unsigned long long #define LL long long #define inf 0x7fffffff #define eps 1e-7 #define N 40009 using namespace std; int m,n,T,t,x,y; vector<pair<int,int> >g[N]; int u[N],v[N],c[N],dist[N]; int p[N][20]; const int mc=18; void init() { for(int i=0; i<=n; i++) { g[i].clear(); } memset(p,-1,sizeof(p));//初始化!! } void dfs(int u,int fa) { for(int i=0; i<g[u].size(); i++) { int v=g[u][i].first; int len=g[u][i].second; if(v!=fa) { dist[v]=dist[u]+len; c[v]=c[u]+1; p[v][0]=u; for(int i=1; i<mc&&p[v][i-1]!=-1; i++) p[v][i]=p[p[v][i-1]][i-1]; dfs(v,u); } } } int lca(int a,int b) { if(c[a]>c[b]) swap(a,b); int t=c[b]-c[a];//WA for(int i=0; t&&i<mc; i++)// if(t&(1<<i)) { b=p[b][i]; t^=(1<<i); } if(a!=b) { for(int i=mc-1; i>=0; i--) { if(p[a][i]!=p[b][i]) a=p[a][i],b=p[b][i]; } a=p[a][0]; } return a; } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); init(); for(int i=1; i<n; i++) { scanf("%d%d%d",&x,&y,&t); g[x].push_back(mp(y,t)); g[y].push_back(mp(x,t)); } for (int i=0; i<m; ++i ) { scanf("%d%d",&u[i],&v[i]); } dist[1]=0; c[1]=0; dfs(1,-1); for(int i=0; i<m; ++i) printf("%d\n",dist[u[i]]+dist[v[i]]-dist[lca(u[i],v[i])]*2); } return 0; }