JZOJ5771【NOIP2008模拟】遨游

 

 

Description

     MWH寒假外出旅游,来到了S国。S国划分为N个省,第i个省有Ti座城市,编号分别为Ci1,Ci2,……CiTi(各省城市编号不会重复)。所有城市间有M条双向的道路连接,从任意一个城市出发,可到达一切城市,每条道路均须收费。
     此时恰逢春运期间,S国交通运输局采取了优惠措施。当一条路的路费在[L..R]区间时,可免去。同时,每个省也有优惠措施,第i个省内的每条道路路费收其Xi%,连接第i个省和第j个省的每条道路路费收其(Xi%+Xj%)/2。
MWH想从城市s走到城市t,请求出一对L,R,确保:

  1. MWH能免费到达目的地;
  2. L≤R;
  3. L、R均为整数;
  4. L尽可能地大,R在满足L最大的前提下最小。



注意:因每条道路由各省的交通运输局直接管辖,所以每条道路的路费必须先得到省级优惠,再得到国家级优惠。
 
 

Input

第一行两个整数N,M。
接下来M行,每行三个整数,u、v、w,表示连接u、v的道路需收费w。
接下来N行,第i+M+1行有一个整数Ti,后面Ti个整数,分别是Ci1..CiTi(所有城市编号保证按正整数顺序给出1..  Ti)。
下一行N个整数X1..Xi。
最后一行,两个整数,s、t。

Output

一行两个整数,如题,L和R。
 

Sample Input

3 7
1 2 3
5 2 8
1 3 7
5 4 5
2 4 9
3 5 10
3 4 2
2 1 2
1 3
2 4 5
30 50 60
1 5
 

Sample Output

2 6


 

Data Constraint


 

 


 

 

想到正解了但是写萎了233.

emmmmm...二分两次,先二分l,跑spfa判断是否S与T联通。

然后再二分r,spfa...

其实不用spfa也行,spfa复杂度有点不好看。、

貌似并查集可以搞一搞, 好像做过类似的题。

 


 

 

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
inline int read() {
    int res=0;char c=getchar();bool f=0;
    while(!isdigit(c)) {if(c=='-')f=1;c=getchar();}
    while(isdigit(c))res=(res<<3)+(res<<1)+(c^48),c=getchar();
    return f?-res:res;
}
#define N 50005
#define M 200005
int n, m, S, T;
struct edge {
    int nxt, to, from;
    double val;
}ed[M*2];
int head[N], cnt;
inline void add(int x, int y, int z)
{
    ed[++cnt].from = x, ed[cnt].to = y;
    ed[cnt].nxt = head[x], ed[cnt].val = z;
    head[x] = cnt;
}
int belong[N];
int youh[N];
int Lans, Rans, l = 1e9, r;

double dis[N];
bool ex[N], can[M*2];
int res;
int pre[N];

inline void spfa()
{
    for (int i = 1 ; i < N ; i ++) dis[i] = 1e9;
    memset(ex, 0, sizeof ex);
    dis[S] = 0;
    queue <int> q;
    q.push(S);
    while(!q.empty())
    {
        int x = q.front();q.pop();
        ex[x] = 0;
        for (register int i = head[x] ; i ; i = ed[i].nxt)
        {
            if (can[i]) continue;
            int to = ed[i].to;
            if (dis[to] > dis[x] + ed[i].val)
            {
                dis[to] = dis[x] + ed[i].val;
                if (!ex[to]) ex[to] = 1, q.push(to);
            }
        }
    }
}

inline bool check(int mid)
{
    memset(can, 0, sizeof can);
    for (register int i = 1 ; i <= cnt ; i ++) if (ed[i].val < (double)mid) can[i] = 1;
    spfa();
    return dis[T] != 1e9;
}

inline bool Check(int mid)
{
    memset(can, 0, sizeof can);
    for (register int i = 1 ; i <= cnt ; i ++) 
    {
        if (ed[i].val < (double)Lans) can[i] = 1;
        if (ed[i].val > (double)mid) can[i] = 1;
    }
    spfa();
    return dis[T] != 1e9;
}

int main()
{
//    freopen("trip.in", "r", stdin);
//    freopen("trip.out", "w", stdout);
    n = read(), m = read();
    for (register int i = 1 ; i <= m ; i ++)
    {
        int x = read(), y = read(), z = read();
        add(x, y, z), add(y, x, z);
    }
    for (register int i = 1 ; i <= n ; i ++)
    {
        int t = read();
        for (register int j = 1 ; j <= t ; j ++)
            belong[read()] = i;
    }
    for (register int i = 1 ; i <= n ; i ++) youh[i] = read();
    S = read(), T = read();
    for (register int i = 1 ; i <= cnt ; i ++)
    {
        int x = ed[i].from, y = ed[i].to;
        ed[i].val = (double)(((double)youh[belong[x]] + (double)youh[belong[y]]) / 200) * ed[i].val;
        r = max(r, (int)ed[i].val + 1);
        l = min(l, max((int)ed[i].val - 1, 0));
    }
    int ll = l, rr = r;
    int mid;
    while(l <= r)
    {
        mid = (l + r) >> 1;
        if (check(mid)) l = mid + 1, Lans = mid;
        else r = mid - 1;
    }
    ll = Lans;
    while(ll <= rr) 
    {
        mid = (ll + rr) >> 1;
        if (Check(mid)) rr = mid - 1, Rans = mid;
        else ll = mid + 1;
    }
    printf("%d %d\n", Lans, Rans);
    return 0;
}

 

posted @ 2018-08-14 19:14  zZhBr  阅读(119)  评论(0编辑  收藏  举报