您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: