POJ 1986 Distance Queries (最近公共祖先,tarjan)
本题目输入格式同1984,这里的数据范围坑死我了!!!1984上的题目说边数m的范围40000,因为双向边,我开了80000+的大小,却RE。
后来果断尝试下开了400000的大小,AC。
题意:给出n个点,m条边。
接下来m行,每行对应u,v,len,字符(字符表示v位于u的哪个方向,在本题没有丝毫用处)
表示u和v的路径长度为len。注意本题是双向边!
给出k个查询,让你求两点间的距离。
思路:可以这样处理:先处理出每个节点i到根的距离dist[i]。
设根节点1到a的路径和1到b的路径的最后一个相同的节点为u,即a和b的最近公共祖先。
那么a和b之间的路径为au+ub。
au+ub=au+dis[u]+ub+dis[u]-2*dis[u]=dis[a]+dis[b]-2*dis[LCA(a,b)]
求最近公共祖先用tarjan算法
还有就是一开始不知道如何将两点之间的距离和对应的查询联系起来,参考了别人的思路后,恍然大悟。
在存储所要查询的内容时,同时记录对应的编号,之后再求LCA时只要将距离存入索引为对应编号的数组中去即可,详细情况见代码吧。
- #include <iostream>
- #include <stdio.h>
- #include <algorithm>
- #include <string.h>
- #include <queue>
- #include <math.h>
- #include <map>
- using namespace std;
- const int maxn=;
- const int INF=0x3f3f3f3f;
- int n,m,k;
- int head[maxn];
- int tot=;
- int dis[maxn]; //存储节点到根节点1的距离
- int vis[maxn]={}; //用于LCA中的标记
- int vis2[maxn]={}; //用于标记是否被访问过
- int result[];
- struct Query{
- int u;
- int id; //该查询对应的编号
- };
- vector<Query>link[maxn];
- struct Edge{
- int next,to,length;
- }edge[maxn*];
- //POJ1984上面说边数大小最多40000,由于双向边,我开了80000+,结果RE,后来开了10倍,才AC。。。
- void add(int u,int v,int l){
- edge[tot].next=head[u];
- edge[tot].to=v;
- edge[tot].length=l;
- head[u]=tot++;
- edge[tot].next=head[v];
- edge[tot].to=u;
- edge[tot].length=l;
- head[v]=tot++;
- }
- struct UF{
- int fa[maxn];
- void init(){
- for(int i=;i<maxn;i++)
- fa[i]=i;
- }
- int find_root(int x){
- if(fa[x]!=x)
- fa[x]=find_root(fa[x]);
- return fa[x];
- }
- void Union(int u,int v){
- int x=find_root(u);
- int y=find_root(v);
- fa[y]=x;
- }
- }uf;
- void LCA(int u){
- vis2[u]=;
- for(int k=head[u];k!=-;k=edge[k].next){
- int v=edge[k].to;
- if(!vis2[v]){
- LCA(v);
- uf.Union(u,v);
- }
- }
- int v,idx,anc;
- vis[u]=;
- for(int i=;i<link[u].size();i++){
- v=link[u][i].u;
- if(vis[v]){
- //idx是u和v所对应的第几个询问
- idx=link[u][i].id;
- anc=uf.fa[uf.find_root(v)];
- result[idx]=dis[u]+dis[v]-*dis[anc];
- }
- }
- }
- void dfs(int u,int l){
- vis2[u]=;
- dis[u]=l;
- for(int k=head[u];k!=-;k=edge[k].next){
- if(!vis2[edge[k].to])
- dfs(edge[k].to,l+edge[k].length);
- }
- }
- int main()
- {
- int u,v,l;
- char str[];
- memset(dis,,sizeof(dis));
- memset(head,-,sizeof(head));
- scanf("%d%d",&n,&m);
- for(int i=;i<=m;i++){
- scanf("%d%d%d%s",&u,&v,&l,str);
- add(u,v,l);
- add(v,u,l);
- }
- cin>>k;
- Query tmp;
- for(int i=;i<=k;i++){
- scanf("%d%d",&u,&v);
- tmp.u=v;tmp.id=i; //这个方法妙啊,在存储查询内容时,记录下对应的编号。
- link[u].push_back(tmp);
- tmp.u=u;
- link[v].push_back(tmp);
- }
- memset(vis2,,sizeof(vis2));
- //先求各节点到根节点的距离
- dfs(,);
- uf.init();
- memset(vis2,,sizeof(vis2));
- //LCA求最近公共祖先
- LCA();
- for(int i=;i<=k;i++){
- printf("%d\n",result[i]);
- }
- return ;
- }
POJ 1986 Distance Queries (最近公共祖先,tarjan)的更多相关文章
- POJ 1986 Distance Queries / UESTC 256 Distance Queries / CJOJ 1129 【USACO】距离咨询(最近公共祖先)
POJ 1986 Distance Queries / UESTC 256 Distance Queries / CJOJ 1129 [USACO]距离咨询(最近公共祖先) Description F ...
- POJ 1986 Distance Queries LCA两点距离树
标题来源:POJ 1986 Distance Queries 意甲冠军:给你一棵树 q第二次查询 每次你问两个点之间的距离 思路:对于2点 u v dis(u,v) = dis(root,u) + d ...
- POJ.1986 Distance Queries ( LCA 倍增 )
POJ.1986 Distance Queries ( LCA 倍增 ) 题意分析 给出一个N个点,M条边的信息(u,v,w),表示树上u-v有一条边,边权为w,接下来有k个询问,每个询问为(a,b) ...
- POJ 1986 Distance Queries 【输入YY && LCA(Tarjan离线)】
任意门:http://poj.org/problem?id=1986 Distance Queries Time Limit: 2000MS Memory Limit: 30000K Total ...
- POJ 1986 Distance Queries (Tarjan算法求最近公共祖先)
题目链接 Description Farmer John's cows refused to run in his marathon since he chose a path much too lo ...
- POJ 1986 Distance Queries(Tarjan离线法求LCA)
Distance Queries Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 12846 Accepted: 4552 ...
- POJ 1986 Distance Queries(LCA Tarjan法)
Distance Queries [题目链接]Distance Queries [题目类型]LCA Tarjan法 &题意: 输入n和m,表示n个点m条边,下面m行是边的信息,两端点和权,后面 ...
- POJ - 1986 Distance Queries(离线Tarjan算法)
1.一颗树中,给出a,b,求最近的距离.(我没考虑不联通的情况,即不是一颗树的情况) 2.用最近公共祖先来求, 记下根结点到任意一点的距离dis[],这样ans = dis[u] + dis[v] - ...
- POJ 1986 - Distance Queries - [LCA模板题][Tarjan-LCA算法]
题目链接:http://poj.org/problem?id=1986 Description Farmer John's cows refused to run in his marathon si ...
随机推荐
- MvvmCross for WPF 支持子窗体显示、关闭、传参
最近在做 PCL(Portable Class Library)平台的项目,所以发一下自己遇到的问题 MvvmCross 是 PCL 平台的一个 MVVM 框架 地址:https://github.c ...
- automapper的简单用法
AutoMapper对象转换方面(Object-Object Mapping)对象映射工具,实现对象和对象之间的转化.主要应用在项目的dto,model,entity或viewmodel之间转换,其实 ...
- hdu 2647 Reward
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2647 Reward Description Dandelion's uncle is a boss o ...
- ajax & jsonp & img
ajax 是一种请求服务器的方式,核心是XMLHttpRequest对象: 优点是无需刷新页面, 缺点是不能跨域请求. /* * Ajax direacted by Zakas * * Ajax.ge ...
- golang:interface{}类型测试
在golang中空的interface即interface{}可以看作任意类型, 即C中的void *. 对interface{}进行类型测试有2种语法: 1. Comma-ok断言: value, ...
- System.IO之内存映射文件共享内存
内存映射文件是利用虚拟内存把文件映射到进程的地址空间中去,在此之后进程操作文件,就 像操作进程空间里的地址一样了,比如使用c语言的memcpy等内存操作的函数.这种方法能够很好的应用在需要频繁处理一个 ...
- Win8.1+vs2012+osg环境搭建
Win8.1+vs2012+osg环境搭建 一. 相关准备 a) Osg源码 当前最新版:OpenSceneGraph-3.2.0.zip 下载链接: http://www.opensceneg ...
- Kinect帮助文档翻译之一 入门
最近在玩Kinect,使用的是Unity,发现网上好像没有什么教程.自己就只有抱着英文版帮助文档啃,真是苦逼 本人英语也不好,大家将就着看吧 Kinect入门帮助 如何运行示例 1 下载并 ...
- C++设计模式系列
该系列主要总结了使用C++来实现各种设计模式,并结合实际的案例来分析如何使用,以及在什么场合下使用设计模式.以下是该系列所有文章的链接.希望对大家有帮助. C++设计模式——简单工厂模式 C++设计模 ...
- Redis基础教程
说明:本文中涉及的代码是c#所写,连接redis的第三方驱动为ServiceStack.Redis.连接redis的客户端软件为redis-desktop-manager. 一.Redis是什么 Re ...