JZOJ5771【NOIP2008模拟】遨游
想到正解了但是写萎了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; }