Codevs 1036 商务旅行
来源:互联网 发布:贪心算法 最优解 编辑:程序博客网 时间:2024/06/05 10:53
1036 商务旅行
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
传送门
题目描述 Description
某首都城市的商人要经常到各城镇去做生意,他们按自己的路线去做,目的是为了更好的节约时间。
假设有N个城镇,首都编号为1,商人从首都出发,其他各城镇之间都有道路连接,任意两个城镇之间如果有直连道路,在他们之间行驶需要花费单位时间。该国公路网络发达,从首都出发能到达任意一个城镇,并且公路网络不会存在环。
你的任务是帮助该商人计算一下他的最短旅行时间。
输入描述 Input Description
输入文件中的第一行有一个整数N,1<=n<=30 000,为城镇的数目。下面N-1行,每行由两个整数a 和b (1<=a, b<=n; a<>b)组成,表示城镇a和城镇b有公路连接。在第N+1行为一个整数M,下面的M行,每行有该商人需要顺次经过的各城镇编号。
输出描述 Output Description
在输出文件中输出该商人旅行的最短时间。
样例输入 Sample Input
5
1 2
1 5
3 5
4 5
4
1
3
2
5
样例输出 Sample Output
7
数据范围及提示 Data Size & Hint
分类标签 Tags
最近公共祖先 图论 并查集 线段树 树结构
/*在线LCA模板.fa[i][j]表示第i个点向上找2^j次所对应的点.所谓原理:2的幂可以组合成任意自然数(包括质数). */#include<iostream>#include<cstdio>#include<cstring>#define MAXN 30001#define D 20using namespace std;struct data{ int v; int next; int z;}e[MAXN*2];int tot,deep[MAXN],fa[MAXN][D+5],n,m,head[MAXN];void add_edge(int u,int v){ tot++; e[tot].v=v; e[tot].next=head[u]; head[u]=tot;}void dfs(int now,int father,int d)//建树. { fa[now][0]=father; deep[now]=d; for(int i=head[now];i;i=e[i].next) { if(father!=e[i].v) { dfs(e[i].v,now,d+1); } }}void get_father()//处理出每个节点的2^j. { for(int j=1;j<=D;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];}int get_same(int a,int b)//二进制使u,v在同一深度.{ for(int i=0;i<=D;i++) if(b&(1<<i)) a=fa[a][i]; return a; }int lca(int u,int v){ if(deep[u]<deep[v]) swap(u,v);//让深的先搜便于计算. u=get_same(u,deep[u]-deep[v]);//lca if(u==v) return u;//u是v父亲时. for(int i=D;i>=0;i--)//向上搜到lca的儿子. if(fa[u][i]!=fa[v][i]) { u=fa[u][i]; v=fa[v][i]; } return fa[u][0];//此时u为lca的子节点.}int main(){ scanf("%d",&n); int x,y; for(int i=1;i<=n-1;i++)//▲一般是n-1条边. { scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x); } dfs(1,1,0); get_father(); int u,v; tot=0; scanf("%d%d",&m,&u); for(int i=1;i<m;i++) { scanf("%d",&v); int LCA=lca(u,v); tot+=(deep[u]+deep[v]-2*deep[LCA]);//数学方法. u=v; } printf("%d",tot); return 0;}
/*离线tarjan+并查集. 第一次打模板Wrong了.然后火急火燎找了半小时错误.关于邻接链表边的标号的初始化问题.若第一条边标号为0则需初始化head[1~n]=-1, 因为搜索的时候必定会搜到head[u]==0 然后需判i!=-1若第一条边编号为1则只需判i!=0 无需初始化.切记. */#include<iostream>#include<cstdio>#include<cstring>#define MAXN 50001using namespace std;int n,m,head[MAXN],ans,fa[MAXN],lc[MAXN],tot,cut,deep[MAXN],head2[MAXN];bool b[MAXN],b2[MAXN];struct data{ int v; int next;}e[MAXN<<1],s[MAXN<<1];void add_edge(int u,int v){ e[tot].v=v; e[tot].next=head[u]; head[u]=tot++;}void add(int u,int v){ s[cut].v=v; s[cut].next=head2[u]; head2[u]=cut++;}void dfs(int x,int father){ deep[x]=deep[father]+1; b[x]=true; for(int i=head[x];i!=-1;i=e[i].next) { if(!b[e[i].v]) dfs(e[i].v,x); }}int find(int x){ if(x==fa[x]) return fa[x]; return fa[x]=find(fa[x]);}void lcatarjan(int u){ fa[u]=u;b[u]=true; for(int i=head[u];i!=-1;i=e[i].next) { if(b[e[i].v]) continue; lcatarjan(e[i].v); fa[find(e[i].v)]=find(u); lc[find(u)]=u; } for(int i=head2[u];i;i=s[i].next) { if(b2[s[i].v]) { ans+=deep[u]+deep[s[i].v]-2*deep[lc[find(s[i].v)]]; } } b2[u]=true;}int main(){ memset(head,-1,sizeof(head)); memset(head2,-1,sizeof(head2)); int x,y; scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x); } int u=1,v; scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%d",&v); add(u,v); add(v,u); u=v; } dfs(1,0); memset(b,0,sizeof(b)); lcatarjan(1); printf("%d",ans); return 0;}
1 0
- Codevs 1036 商务旅行
- 【codevs 1036】商务旅行
- Codevs 1036 商务旅行
- codevs 1036 商务旅行
- 【codevs 1036】商务旅行
- 【codevs 1036】商务旅行
- codevs 1036 商务旅行 (lca)
- codevs 1036 商务旅行 题解报告
- codevs 1036 商务旅行 (LCA)
- 【LCA 倍增法】【codevs 1036 商务旅行】
- Codevs 1036:商务旅行——题解
- CodeVs.1036 商务旅行 ( LCA 最近公共祖先 )
- codevs 1036 商务旅行 LCA 解题报告
- Codevs P1036 商务旅行
- 1036商务旅行
- 1036 商务旅行
- 1036 商务旅行
- 1036 商务旅行
- Express 4.x API
- 考研准备
- 原来Github上的README.md文件这么有意思——Markdown语言详解
- splay树
- Doxygen使用教程(个人总结)
- Codevs 1036 商务旅行
- 15.REST 风格的路由规则
- 被公司辞了
- myeclipse使用经验---生成WAR包并在Tomcat下部署发布
- 2016年6月27日--2016年7月8日(1小时,剩2939小时)
- java设置一段代码执行超时时间
- apache所有开源项目文件
- Apple Watch 开发详解
- SmartFoxServer 2X服务器应用开发基础