Codeforces 230D Planets【思维+SPFA】

D. Planets
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Goa'uld Apophis captured Jack O'Neill's team again! Jack himself was able to escape, but by that time Apophis's ship had already jumped to hyperspace. But Jack knows on what planet will Apophis land. In order to save his friends, Jack must repeatedly go through stargates to get to this planet.

Overall the galaxy has n planets, indexed with numbers from 1 to n. Jack is on the planet with index 1, and Apophis will land on the planet with index n. Jack can move between some pairs of planets through stargates (he can move in both directions); the transfer takes a positive, and, perhaps, for different pairs of planets unequal number of seconds. Jack begins his journey at time 0.

It can be that other travellers are arriving to the planet where Jack is currently located. In this case, Jack has to wait for exactly 1 second before he can use the stargate. That is, if at time t another traveller arrives to the planet, Jack can only pass through the stargate at time t + 1, unless there are more travellers arriving at time t + 1 to the same planet.

Knowing the information about travel times between the planets, and the times when Jack would not be able to use the stargate on particular planets, determine the minimum time in which he can get to the planet with index n.

Input

The first line contains two space-separated integers: n (2 ≤ n ≤ 105), the number of planets in the galaxy, and m (0 ≤ m ≤ 105) — the number of pairs of planets between which Jack can travel using stargates. Then m lines follow, containing three integers each: the i-th line contains numbers of planets ai and bi (1 ≤ ai, bi ≤ nai ≠ bi), which are connected through stargates, and the integer transfer time (in seconds) ci (1 ≤ ci ≤ 104) between these planets. It is guaranteed that between any pair of planets there is at most one stargate connection.

Then n lines follow: the i-th line contains an integer ki (0 ≤ ki ≤ 105) that denotes the number of moments of time when other travellers arrive to the planet with index i. Then ki distinct space-separated integers tij (0 ≤ tij < 109) follow, sorted in ascending order. An integer tijmeans that at time tij (in seconds) another traveller arrives to the planet i. It is guaranteed that the sum of all ki does not exceed 105.

Output

Print a single number — the least amount of time Jack needs to get from planet 1 to planet n. If Jack can't get to planet n in any amount of time, print number -1.

Examples
input
4 6
1 2 2
1 3 3
1 4 8
2 3 4
2 4 5
3 4 3
0
1 3
2 3 4
0
output
7
input
3 1
1 2 3
0
1 3
0
output
-1
Note

In the first sample Jack has three ways to go from planet 1. If he moves to planet 4 at once, he spends 8 seconds. If he transfers to planet 3, he spends 3 seconds, but as other travellers arrive to planet 3 at time 3 and 4, he can travel to planet 4 only at time 5, thus spending 8 seconds in total. But if Jack moves to planet 2, and then — to planet 4, then he spends a total of only 2 + 5 = 7 seconds.

In the second sample one can't get from planet 1 to planet 3 by moving through stargates.


题目大意:


我们要找一条从1到N的最短路。

现在每个点都会在一些时间关闭通道,这些时间不能在这些点上。


思路:


在SPFA过程中,更新点v的最短路时,判断一下当前时间是否处于不能通过的时间上,这里对于每个点来讲,我们都进行一次二分查找即可。

如果这个点处于可以通过时间上,那么直接更新,否则延迟即可,延迟到的时间我们预处理一下就行了。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
vector<int>mp[150000];
vector<int>nex[150000];
struct node
{
    int from,to,next,w;
}e[5151111];
int n,m,cont;
int head[150000];
void add(int from,int to,int w)
{
    e[cont].to=to;
    e[cont].w=w;
    e[cont].next=head[from];
    head[from]=cont++;
}
/*************************************/
int find(int v,int t)
{
    int l=0;
    int r=mp[v].size()-1;
    while(r-l>=0)
    {
        int mid=(l+r)/2;
        if(mp[v][mid]>t)
        {
            r=mid-1;
        }
        else if(mp[v][mid]<t)
        {
            l=mid+1;
        }
        else
        {
            return nex[v][mid];
        }
    }
    return t;
}
int dist[150000];
int vis[150000];
void SPFA()
{
    queue<int>s;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)dist[i]=0x3f3f3f3f;
    dist[1]=find(1,0);
    s.push(1);
    while(!s.empty())
    {
        int u=s.front();
        vis[u]=0;
        s.pop();
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            int ttt=dist[u]+w;
            if(v!=n)ttt=find(v,ttt);
            if(dist[v]>ttt)
            {
                dist[v]=ttt;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    s.push(v);
                }
            }
        }
    }
    if(dist[n]==0x3f3f3f3f)printf("-1\n");
    else printf("%d\n",dist[n]);
}
/*************************************/
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        cont=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)mp[i].clear(),nex[i].clear();
        for(int i=1;i<=m;i++)
        {
            int x,y,w;scanf("%d%d%d",&x,&y,&w);
            add(x,y,w);
            add(y,x,w);
        }
        for(int i=1;i<=n;i++)
        {
            int k;scanf("%d",&k);
            while(k--)
            {
                int v;scanf("%d",&v);
                mp[i].push_back(v);
            }
            for(int j=mp[i].size()-1;j>=0;j--)
            {
                int pre;
                if(j==mp[i].size()-1||mp[i][j]!=mp[i][j+1]-1)
                {
                    pre=mp[i][j]+1;
                    nex[i].push_back(mp[i][j]+1);
                }
                else nex[i].push_back(pre);
            }
            reverse(nex[i].begin(),nex[i].end());
        }
        SPFA();
    }
}






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值