hdu 2586 How far away ?(在线LCA+离线Tarjan)
2017-08-08 09:06
417 查看
How far away ?
题目链接:How far away ?题意:一个村子里有n个房子,这n个房子用n-1条路连接起来,接下了有m次询问,每次询问两个房子a,b之间的最短距离是多少。
思路:LCA模板题
代码(离线Tarjan):
#include<stdio.h> #include<string.h> #include<vector> #include<algorithm> using namespace std; const int maxn=4e4+210; vector<int>v[maxn],query[maxn],num[maxn],w[maxn]; int pre[maxn],dis[maxn],ans[maxn]; bool vis[maxn]; int n,m; void Init() { for(int i=1;i<=n;++i) { v[i].clear(); query[i].clear(); num[i].clear(); w[i].clear(); pre[i]=i; dis[i]=0; vis[i]=false; } } int Find(int x) { if(x!=pre[x]) pre[x]=Find(pre[x]); return pre[x]; } void join(int x,int y) { int fx=Find(x),fy=Find(y); if(fx!=fy) pre[fy]=fx; } void Tarjan(int rt,int val) { vis[rt]=true; dis[rt]=val; for(int i=0;i<v[rt].size();++i) { int tmp=v[rt][i]; if(!vis[tmp]) { Tarjan(tmp,val+w[rt][i]); join(rt,tmp); } } for(int i=0;i<query[rt].size();++i) { int tmp=query[rt][i]; if(vis[tmp]) ans[num[rt][i]]=dis[rt]+dis[tmp]-2*dis[Find(tmp)]; } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); Init(); int x,y,val; for(int i=1;i<n;++i) { scanf("%d%d%d",&x,&y,&val); v[x].push_back(y); w[x].push_back(val); v[y].push_back(x); w[y].push_back(val); } for(int i=1;i<=m;++i) { scanf("%d%d",&x,&y); query[x].push_back(y); num[x].push_back(i); query[y].push_back(x); num[y].push_back(i); } Tarjan(1,0); for(int i=1;i<=m;++i) printf("%d\n",ans[i]); } return 0; }
这个很简单,时间复杂度O(N+Q),ve
109c2
ctor可以用邻接表优化一下
大神博客详解:离线Tarjan
代码(在线RMQ+DFS序):
#include<stdio.h> #include<math.h> #include<string.h> #include<algorithm> using namespace std; const int maxn=4e4+10; struct edge { int v,w,next,flag; } E[maxn<<1]; int first[maxn],val[maxn],dep[maxn],a[maxn<<1],b[maxn],f[maxn<<1][20],lca[maxn<<1][20]; int top,len,n,m; void dfs(int x,int step,int va) { dep[x]=step; a[++top]=x,val[x]=va; for(int i=first[x]; ~i; i=E[i].next) { if(E[i].flag) continue; E[i].flag=E[i^1].flag=1; int v=E[i].v,w=E[i].w; dfs(v,step+1,va+w); a[++top]=x; } } void init() { for(int i=1; i<=top; ++i) { f[i][0]=dep[a[i]]; lca[i][0]=a[i]; } int s=(int)log2(top*1.0); for(int j=1; j<=s; ++j) { int k=top-(1<<j)+1; for(int i=1; i<=k; ++i) { int x=i+(1<<(j-1)); if(f[i][j-1]<=f[x][j-1]) { f[i][j]=f[i][j-1]; lca[i][j]=lca[i][j-1]; } else { f[i][j]=f[x][j-1]; lca[i][j]=lca[x][j-1]; } } } } void add_edge(int u,int v,int w) { E[len].v=v,E[len].w=w,E[len].flag=0,E[len].next=first[u],first[u]=len++; } int main() { int t; scanf("%d",&t); while(t--) { memset(b,0,sizeof(b)); memset(first,-1,sizeof(first)); scanf("%d%d",&n,&m); len=0,top=0; int u,v,w; for(int i=1; i<n; ++i) { scanf("%d%d%d",&u,&v,&w); add_edge(u,v,w); add_edge(v,u,w); } dfs(1,1,0); for(int i=1; i<=top; ++i) if(b[a[i]]==0) b[a[i]]=i; init(); while(m--) { scanf("%d%d",&u,&v); u=b[u],v=b[v]; if(u>v) swap(u,v); int j=(int)log2((v-u)*1.0); int i=v-(1<<j)+1; int fa=f[u][j]<f[i][j]?lca[u][j]:lca[i][j]; printf("%d\n",val[a[u]]+val[a[v]]-2*val[fa]); } } return 0; }
在线算法把一棵树转化为了一维数组,a[]表示树上的节点在数组中的位置,b[]表示树上的节点在数组中第一次出现的位置
则任意两个节点i和j,在[abi,abj]中深度最小的那个节点就是他们的最近公共祖先
预处理的时间复杂度O(nlog2n),查询O(1)
大神博客详解:求LCA最近公共祖先的在线ST算法
相关文章推荐
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(在线LCA+离线Tarjan)
- hdu 2586 How far away ?(离线tarjan求LCA)
- hdu 2586 How far away ? (LCA 离线tarjan)
- HDU 2586 How far away? LCA 离线tarjan
- HDU2586 How far away ?(最近公共祖先lca,离线Tarjan,最短路)
- HDU 2586 How far away ? LCA离线tarjan思想
- HDU - 2586 How far away ?(tarjan离线做法求lca)