hdu 5361 最短路+并查集优化

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  (1in)
 

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  (1n2×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 (0lirin,1ci109)
 

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();
		
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值