In Touch
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2302 Accepted Submission(s): 617
Problem Description
There are n soda living in a straight line. soda are numbered by
1,2,…,n
from left to right. The distance between two adjacent soda is 1 meter. Every soda has a teleporter. The teleporter of
i
-th soda can teleport to the soda whose distance between
i
-th soda is no less than
li
and no larger than
ri
. The cost to use
i
-th soda's teleporter is
ci
.
The 1 -st soda is their leader and he wants to know the minimum cost needed to reach i -th soda (1≤i≤n) .
The 1 -st soda is their leader and he wants to know the minimum cost needed to reach i -th soda (1≤i≤n) .
Input
There are multiple test cases. The first line of input contains an integer
T
, indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤2×105) , the number of soda.
The second line contains n integers l1,l2,…,ln . The third line contains n integers r1,r2,…,rn . The fourth line contains n integers c1,c2,…,cn . (0≤li≤ri≤n,1≤ci≤109)
The first line contains an integer n (1≤n≤2×105) , the number of soda.
The second line contains n integers l1,l2,…,ln . The third line contains n integers r1,r2,…,rn . The fourth line contains n integers c1,c2,…,cn . (0≤li≤ri≤n,1≤ci≤109)
Output
For each case, output
n
integers where
i
-th integer denotes the minimum cost needed to reach
i
-th soda. If
1
-st soda cannot reach
i
-the soda, you should just output -1.
Sample Input
1 5 2 0 0 0 1 3 1 1 0 5 1 1 1 1 1
Sample Output
0 2 1 1 -1HintIf you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
Author
zimpha@zju
Source
Recommend
wange2014
题目大意:
有N个点排成一排,相邻两个点之间距离为1,每个点可以花费ci到达距离不小于li,不大于ri的点。求第一个点到其他点的距离。
解题思路:
从最朴素的dijkstra开始思考,为了求出单源最短路,我们需要不断找出未确定的点中到原点距离最小的点。这个图中每个点的出边权值都一样,所以它所指向的点v通过这个点u的距离一定是dist[u]+cost[u],所以我们就可以用一个优先队列维护已经确定的点,dist[u]+cost[u]小的优先出队。但是这样还是不行,如果每个点所指向的区间非常大的话,复杂度最坏就能达到O(N^2 * log N)了。于是我们需要继续优化。
按照刚才的方式更新,每个点一定是在第一次更新的时候dist最小,所以就可以找一个方法让它在第一次更新后就不再考虑。很容易想到的就是set,确实也有很多人是用set写的,不过还有更快的方法,就是用并查集。对于已经更新过的区间我们可以用一个并查集合并,根节点设定为区间最右边的下一个点。这样我们从左往右扫更新dist的时候,如果遇到更新过的区间就可以通过根节点直接跳过区间。那么总复杂度就是O(N * log N)。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <stack>
#include <deque>
#include <string>
#include <map>
#include <set>
#include <list>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define LL long long
#define fi first
#define se second
#define mem(a,b) memset((a),(b),sizeof(a))
#pragma comment(linker, "/STACK:102400000,102400000")
const int MAXV=200000+3;
int V, l[MAXV], r[MAXV];
LL cost[MAXV];
LL dis[MAXV];
int par[MAXV];
struct Node
{
int u;
Node(int u):u(u){}
bool operator < (const Node &other)const
{
return dis[u]+cost[u]>dis[other.u]+cost[other.u];
}
};
void init()//初始化
{
for(int i=0;i<=V;++i)//一定要多初始化一个点,因为会合并区间右端点的下一个点
{
dis[i]=INF;
par[i]=i;
}
}
int findfather(int x)
{
return par[x]=par[x]==x?x:findfather(par[x]);
}
void unite(int a,int b)//让最右边的点做根节点
{
int fa=findfather(a), fb=findfather(b);
if(fa!=fb)
par[fa]=fb;
}
void dijkstra(int s)
{
priority_queue<Node> que;
que.push(Node(s));
dis[s]=0;
unite(0,1);
while(!que.empty())
{
int u=que.top().u; que.pop();
for(int i=-1;i<2;i+=2)//分别处理左右两个区间
{
int left=u+l[u]*i, right=u+r[u]*i;
if(left>right)
swap(left, right);
left=max(left, 0);
right=min(right, V-1);
for(;left<=right;++left)
{
left=findfather(left);//移动到已经更新过的区间的右边
if(left>right)
break;
dis[left]=dis[u]+cost[u];//这里一定是未更新的点
que.push(Node(left));
unite(left, left+1);
}
}
}
}
int main()
{
int T_T;
scanf("%d",&T_T);
while(T_T--)
{
scanf("%d", &V);
init();
for(int i=0;i<V;++i)
scanf("%d",&l[i]);
for(int i=0;i<V;++i)
scanf("%d",&r[i]);
for(int i=0;i<V;++i)
scanf("%lld",&cost[i]);
dijkstra(0);
for(int i=0;i<V;++i)
printf("%lld%c",dis[i]==INF?-1:dis[i], i==V-1?'\n':' ');
}
return 0;
}