Distance Queries
时间限制: 1 Sec 内存限制: 128 MB
题目描述
约翰的奶牛们拒绝跑他的马拉松,因为她们悠闲的生活不能承受他选择的长长的赛道。因此他决心找一条更合理的赛道。此题的输入于第一题相同,紧接着下一行输入一个整数K,以后K行为K个"距离问题"。每个距离问题包括两个整数,就是约翰感兴趣的两个农场的编号,请你尽快算出这两地之间的距离。
N个点,N-1条边
输入
第1行:两个分开的整数:N和M;
第2..M+1行:每行包括4个分开的内容,F1,F2,L,D分别描述两个农场的编号,道路的长度,F1到F2的方向(N,E,S,W)。
第2+M行:一个整数K。(1<=k<=10,000)
第3+M..2+M+K:每行表示一个问题,包含两个整数代表两个农场。
输出
第1..K行:对应每个问题,输出单独的一个整数给出正确的距离。
样例输入
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6
样例输出
13
3
36
提示
农场2 到6 有 20+3+13=36 的距离。
题解:
首先不得不吐槽一下这道题输入数据中的方向没什么用……
然后由于这道题需要用到LCA求最近公共祖先的算法,在这里分享一下连接:倍增算法 tarjan算法。
了解了算法之后,这道题就很容易解决了,我用的是tarjan算法(个人觉得比较好理解)。
1.用邻接链表建图。
2.用邻接链表存储每一个询问。(本人在这里尝试了一下STL中的vector存图,稍后介绍)
3.维护一个dis数组保存到根节点的距离。
4.每一次求出一个LCA后用dis[root]+dis[y]-dis[lca]*2来求出两点之间的距离。(原理也很简单,两个点到根节点的距离和减去最近公共祖先到根节点的距离就是这两个节点的距离)
5.按照题目要求的顺序输出结果就行了。
以上是这道题目的说明,下面我们浅谈vector的用法:
1.vector是C++中一个十分有用的容器,实际上是一个没有容量限制的数组。(但是比较耗时间,事实上STL模版基本上都比手打的要耗时)
2.定义在头文件#include<vector>中。
3.在程序中用vector<"类型">"名称";来定义。如果是vector<int>mem[101];表示的就是一个int类型的二维数组。(当然,类型可以为其他类型,包括结构体)
4.当前容量大小:mem.size();
清空:mem.clear();
插入元素:mem.insert(mem.begin()+i,a);在第i+1个元素前加上a。
删除元素:mem.erase(mem.begin()+i);删除第i+1个元素。
5.使用迭代访问器访问元素:j为地址类型。
vector<student>::iterator j; for(j=q[root].begin();j!=q[root].end();j++) { cout<<*j<<endl; }
6.使用下标访问元素
int end=mem.size(); for(i=0;i<end;i++) { cout<<mem[i]<<endl; }
好了,说了这么多,终于可以上代码了,以下是AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> #include<ctime> #include<queue> #include<stack> #include<vector> using namespace std; const int N=40001; const int M=10001; int n,m,l; struct node { int next,to,dis; }edge[2*N]; int head[N],size,vis[N],ans[M],dis[N],father[N]; struct student { int x,id; }; vector<student>q[N]; void putin(int from,int to,int dis) { size++; edge[size].next=head[from]; edge[size].to=to; edge[size].dis=dis; head[from]=size; } int find(int x) { if(father[x]==x)return x; else { father[x]=find(father[x]); return father[x]; } } void dfs(int root) { vis[root]=1; vector<student>::iterator j; for(j=q[root].begin();j!=q[root].end();j++) { int y=j->x; if(vis[y]) { int p=j->id; int lca=find(y); ans[p]=dis[root]+dis[y]-2*dis[lca]; } } for(int i=head[root];i;i=edge[i].next) { int y=edge[i].to; if(!vis[y]) { dis[y]=dis[root]+edge[i].dis; dfs(y); father[y]=root; } } } int main() { int i,j,from,to,dis; char s[2]; scanf("%d%d",&n,&m); for(i=1;i<=m;i++) { scanf("%d%d%d%s",&from,&to,&dis,s); putin(from,to,dis);putin(to,from,dis); } scanf("%d",&l); for(i=1;i<=l;i++) { scanf("%d%d",&from,&to); q[from].push_back((student){to,i}); q[to].push_back((student){from,i}); } for(i=1;i<=n;i++)father[i]=i; dfs(1); for(i=1;i<=l;i++) { printf("%d\n",ans[i]); } return 0; }