hdu 5361 2015多校联赛第六场 In Touch
2016-07-09 16:31
369 查看
题意:
每个点可以到左右两个范围内的点并花费为Ci, 问1 到 所有点的最短距离。
用普通的优先队列最短路不行,复杂度高,且边较多。
、
这里要用dijstra的一个性质,那就是在未使用过的点中挑选出离S最近的 X,之后这个X不会再更新,如果用优先队列来写的话就表现为从队列里出来的点不会再被更新
我们设到达V点最近的距离为dis[v], 如果我们把 dis[v] + C[V](和小的优先) 放入优先队列,那么取出来的点去更新它能到达的区间,这些区间内的点必然是最小的,也就是说,这个点能到的区间内的点之后都不不要再更新,为了避免在更新这个点,我们可以将已经更新的点用并查集,这样在下次需要更新这段区间时,我们就可跳过这段区间,直接更新到区间的又端点。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2*1e5+10;
typedef long long LL;
LL L[maxn];
LL R[maxn];
LL dis[maxn];
int f[maxn];
#pragma comment(linker, "/STACK:1024000000,1024000000")
LL c[maxn];
int n;
struct node
{
int id ;
LL dis;
node(int a ,LL b):id(a),dis(b) {};
friend bool operator < (node a,node b)
{
return a.dis>b.dis;
}
};
int find(int x)
{
if (x != f[x])
f[x] = find(f[x]);
return f[x];
}
void Merge(int x,int y)
{
int bossx = find(x);
int bossy = find(y);
if(bossx!=bossy)
{
f[bossx] = bossy;
}
}
void dijkstra(int s)
{
dis[1] = 0;
priority_queue<node>q;
q.push(node(s,c[s]));
while(!q.empty())
{
node now = q.top();
q.pop();
// int u = now.id;
for(int i = -1; i<2; i+=2)
{
int zuo = now.id+ i*L[now.id];
int you = now.id+ i*R[now.id];
if(zuo>you)
swap(zuo,you);
zuo = max(1,zuo);
you = min(you,n);
for(int j = zuo; j<=you; j++)
{
j = find(j);
if(j>you)
break;
if(dis[j]>now.dis)
{
dis[j] = now.dis;
q.push(node(j,dis[j]+c[j]));
}
if(j+1<you)
Merge(j,j+1);
}
}
}
}
const long long INF = 1e17;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = 1; i<=n; i++)
{
scanf("%lld",&L[i]);
f[i] = i;
dis[i] = INF;
}
for(int i = 1; i<=n; i++)
{
scanf("%lld",&R[i]);
}
for(int i = 1; i<=n; i++)
{
scanf("%lld",&c[i]);
}
dijkstra(1);
for(int i = 1; i<n; i++)
{
if(dis[i]==INF)
{
dis[i]=-1;
}
printf("%lld ",dis[i]);
}
if(dis
==INF)
dis
= -1;
cout<<dis
<<endl;
}
return 0;
}
每个点可以到左右两个范围内的点并花费为Ci, 问1 到 所有点的最短距离。
用普通的优先队列最短路不行,复杂度高,且边较多。
、
这里要用dijstra的一个性质,那就是在未使用过的点中挑选出离S最近的 X,之后这个X不会再更新,如果用优先队列来写的话就表现为从队列里出来的点不会再被更新
我们设到达V点最近的距离为dis[v], 如果我们把 dis[v] + C[V](和小的优先) 放入优先队列,那么取出来的点去更新它能到达的区间,这些区间内的点必然是最小的,也就是说,这个点能到的区间内的点之后都不不要再更新,为了避免在更新这个点,我们可以将已经更新的点用并查集,这样在下次需要更新这段区间时,我们就可跳过这段区间,直接更新到区间的又端点。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2*1e5+10;
typedef long long LL;
LL L[maxn];
LL R[maxn];
LL dis[maxn];
int f[maxn];
#pragma comment(linker, "/STACK:1024000000,1024000000")
LL c[maxn];
int n;
struct node
{
int id ;
LL dis;
node(int a ,LL b):id(a),dis(b) {};
friend bool operator < (node a,node b)
{
return a.dis>b.dis;
}
};
int find(int x)
{
if (x != f[x])
f[x] = find(f[x]);
return f[x];
}
void Merge(int x,int y)
{
int bossx = find(x);
int bossy = find(y);
if(bossx!=bossy)
{
f[bossx] = bossy;
}
}
void dijkstra(int s)
{
dis[1] = 0;
priority_queue<node>q;
q.push(node(s,c[s]));
while(!q.empty())
{
node now = q.top();
q.pop();
// int u = now.id;
for(int i = -1; i<2; i+=2)
{
int zuo = now.id+ i*L[now.id];
int you = now.id+ i*R[now.id];
if(zuo>you)
swap(zuo,you);
zuo = max(1,zuo);
you = min(you,n);
for(int j = zuo; j<=you; j++)
{
j = find(j);
if(j>you)
break;
if(dis[j]>now.dis)
{
dis[j] = now.dis;
q.push(node(j,dis[j]+c[j]));
}
if(j+1<you)
Merge(j,j+1);
}
}
}
}
const long long INF = 1e17;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = 1; i<=n; i++)
{
scanf("%lld",&L[i]);
f[i] = i;
dis[i] = INF;
}
for(int i = 1; i<=n; i++)
{
scanf("%lld",&R[i]);
}
for(int i = 1; i<=n; i++)
{
scanf("%lld",&c[i]);
}
dijkstra(1);
for(int i = 1; i<n; i++)
{
if(dis[i]==INF)
{
dis[i]=-1;
}
printf("%lld ",dis[i]);
}
if(dis
==INF)
dis
= -1;
cout<<dis
<<endl;
}
return 0;
}
相关文章推荐
- mongodb 运行时添加新的分片复制集
- 105---oracle的 函数,转换函数, 分析函数, 表空间,系统用户, 权限和角色, 序列, 同义词, 索引,表分区,,,
- python学习——使用dict和set
- Android 中 Activity的生命周期 和 Log输出
- 【android学习笔记】读取SD卡
- 自定义的一个titleview,懒得每次都写title
- sql server高效分页
- hdu 4544 湫湫系列故事——消灭兔子 贪心+优先队列 解题报告
- 单粒模式
- 数组指针和指针数组的区别
- cocos2d-x 3.x学习之拖动滑块类
- 104----oracle基本概念,启动,连接, 数据类型,常见案例,集合操作符
- 用 Python 进行数据分析,不懂 Python,求合适的 Python 书籍或资料推荐?
- Asteroids!
- Nginx处理HTTP请求的路由过程
- AFNetworking 3.0 版本使用
- 简单排序之简单选择排序
- JS利用正则配合replace替换指定字符
- Linux C第二课
- Velocity 页面进行加减法