1. 程式人生 > >JZOJ5771【NOIP2008模擬】遨遊

JZOJ5771【NOIP2008模擬】遨遊

免費 lan fab ubd elong vsm aws rgs vob

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

JZOJ5771【NOIP2008模擬】遨遊