In Touch
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2878 Accepted Submission(s): 761
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 -1
Hint
If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
Author
zimpha@zju
题意: 给你 n 个点 然后 给你 每一个点 的l[i] 和 r[i] 表示 从这个点走 最少走 l[i] 步 最多 走 r[i] 步 然后花费为 c[i] 问你从1 点走到其他点的最小花费 如果不能达到就输出-1 。
思路: 当然很容易想到最短路,但是 每一个点 可以到达的点数 可能是n ,所以跑一般的最短路就一定会 爆时间的。
但是这里有一个条件我们可以发现 就是从一个点 出发 的路径 花费都是一定的 那么 如果用dij 跑的话 如果跑过这个点,那么
那么到这个点的距离就一定是最短的,肯定不会再被松弛。 那么下次 搜到这个点的话我们就可以转到 他的右边第一个没有被搜
过的点, 那么我们 就可以想到 如果搜到了这个点, 那么就可以将这个点和他后边的那个点 缩成一个点。 那么每次找到的时候
找到的都是该点后边第一个没有被搜过的点,那么这样就大大的降低了复杂度。 但是还有一个要注意的点就是 我们 每次放进
优先队列的花费不是当前点的最短距离 而是 当前点的最短距离和从他出去的花费。 不然 假设 v1 点的距离 为 12 v2 点的
距离为13 但是从v1 点出去的花费为1 从 v2 点出去的花费 为9 (队列中有这两个点 ) 那么下一个最短的肯定是 从v1 出去
到达的点。
代码:
#include<bits/stdc++.h>
#define N 200005
using namespace std;
typedef long long ll;
const ll inf=1e18+5;
ll dis[N];
ll c[N];
int lt[N],rt[N];
int f[N];
int n;
struct qnode
{
int u;
ll c;
qnode(int _u=0,ll _c=0 ):u(_u),c(_c){}
bool operator <(const qnode &a ) const
{
return a.c<c;
}
};
struct node
{
int v;
ll c;
node (int _v=0,ll _c=0 ):v(_v),c(_c){}
};
vector< node >ve[N];
void init()
{
for(int i=0;i<=n+2;i++){
f[i]=i;
ve[i].clear();
dis[i]=inf;
}
return ;
}
int getf(int x){
return f[x]==x?x:(f[x]=getf(f[x]));
}
void merge(int x,int y)
{
int t1=getf(x);
int t2=getf(y);
if(t1!=t2)
{
f[t1]=t2;
}
return ;
}
void dij()
{
dis[1]=0;
priority_queue<qnode >que;
que.push(qnode(1,c[1]));
qnode tmp;
int ln,rn;
int u,v;
while(!que.empty())
{
tmp=que.top(); que.pop();
u=tmp.u;
//cout<<u<<endl;
for(int i=-1;i<=1;i+=2)
{
rn=n; ln=1;
if(i==1){
rn=min(rn,u+rt[u]);
ln=max(ln,u+lt[u]);
}
else
{
rn=min(rn,u-lt[u]);
ln=max(ln,u-rt[u]);
}
if(ln>rn) continue;
//cout<<"l: "<<ln<<"r : "<<rn <<endl;
v=ln;
while(v<=rn)
{
v=getf(v);
//printf("v: %d\n",v);
if(v>rn) break;
if(dis[v]>dis[u]+c[u])
{
// cout<<"lalala"<<endl;
dis[v]=dis[u]+c[u];
que.push(qnode(v,dis[v]+c[v]));
merge(v,v+1);
}
v=v+1;
}
}
}
printf("0");
for(int i=2;i<=n;i++)
{
if(dis[i]==inf) printf(" -1");
else printf(" %lld",dis[i]);
}
printf("\n");
return ;
}
int main()
{
int cas;
cin>>cas;
while(cas--)
{
cin>>n;
init();
for(int i=1;i<=n;i++) scanf("%d",<[i]);
for(int i=1;i<=n;i++) scanf("%d",&rt[i]);
for(int i=1;i<=n;i++) scanf("%lld",&c[i]);
dij();
}
}