【BZOJ1050】[HAOI2006]旅行comf

Description

  给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000)。给你两个顶点S和T
,求一条路径,使得路径上最大边和最小边的比值最小。如果S和T之间没有路径,输出”IMPOSSIBLE”,否则输出
这个比值,如果需要,表示成一个既约分数。 备注: 两个顶点之间可能有多条路径。

Input

  第一行包含两个正整数,N和M。下来的M行每行包含三个正整数:x,y和v。表示景点x到景点y之间有一条双向
公路,车辆必须以速度v在该公路上行驶。最后一行包含两个正整数s,t,表示想知道从景点s到景点t最大最小速
度比最小的路径。s和t不可能相同。
1<N<=500,1<=x,y<=N,0<v<30000,0<M<=5000

Output

  如果景点s到景点t没有路径,输出“IMPOSSIBLE”。否则输出一个数,表示最小的速度比。如果需要,输出一
个既约分数。

Sample Input

【样例输入1】
4 2
1 2 1
3 4 2
1 4
【样例输入2】
3 3
1 2 10
1 2 5
2 3 8
1 3
【样例输入3】
3 2
1 2 2
2 3 4
1 3

Sample Output

【样例输出1】
IMPOSSIBLE
【样例输出2】
5/4
【样例输出3】
2

Solution

两种做法:

1. O(m^2)的暴力

我们发现一个性质:答案一定是排序后一个后缀的最小生成树。所以暴力就是直接枚举每个后缀跑最小生成树。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 
 6 #ifdef WIN32
 7     #define LL "%I64d"
 8 #else
 9     #define LL "%lld"
10 #endif
11 
12 #ifdef CT
13     #define debug(...) printf(__VA_ARGS__)
14     #define setfile() 
15 #else
16     #define debug(...)
17     #define filename ""
18     #define setfile() freopen(filename".in", "r", stdin); freopen(filename".out", "w", stdout)
19 #endif
20 
21 #define R register
22 #define getc() (S == T && (T = (S = B) + fread(B, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
23 #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
24 #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
25 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
26 #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
27 #define cabs(_x) ((_x) < 0 ? (- (_x)) : (_x))
28 char B[1 << 15], *S = B, *T = B;
29 inline int F()
30 {
31     R char ch; R int cnt = 0; R bool minus = 0;
32     while (ch = getc(), (ch < '0' || ch > '9') && ch != '-') ;
33     ch == '-' ? minus = 1 : cnt = ch - '0';
34     while (ch = getc(), ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
35     return minus ? -cnt : cnt;
36 }
37 #define maxn 510
38 #define maxm 5010
39 struct Edge
40 {
41     int a, b, w;
42     inline bool operator < (const Edge &that) const {return w < that.w;}
43 }e[maxm];
44 int Fa[maxn], n, m;
45 inline void init()
46 {
47     for (R int i = 1; i <= n; ++i) Fa[i] = i;
48 }
49 int gcd(R int a, R int b) {return !b ? a : gcd(b, a % b);}
50 int Find(R int x) {return Fa[x] == x ? x : Fa[x] = Find(Fa[x]);}
51 int main()
52 {
53 //    setfile();
54     n = F(), m = F();
55     for (R int i = 1; i <= m; ++i)
56         e[i] = (Edge) {F(), F(), F()};
57     R int s = F(), t = F();
58     std::sort(e + 1, e + m + 1);
59     R int ans1 = 1, ans2 = 0;
60     for (R int i = 1; i <= m; ++i)
61     {
62         init();
63         R int up;
64         R bool flag = 1;
65         for (R int j = i; j <= m && flag; ++j)
66         {
67             R int f1 = Find(e[j].a), f2 = Find(e[j].b);
68             if (f1 != f2) Fa[f1] = f2;
69             if (Find(s) == Find(t)) flag = 0, up = e[j].w;
70         }
71         if (i == 1 && flag) return puts("IMPOSSIBLE"), 0;
72         if (!flag && (double) up / e[i].w < (double) ans1 / (double) ans2)
73         {
74             ans1 = up;
75             ans2 = e[i].w;
76         }
77     }
78     if (ans1 % ans2 == 0) printf("%d\n", ans1 / ans2 );
79     else printf("%d/%d\n", ans1 / gcd(ans1, ans2), ans2 / gcd(ans1, ans2) );
80     return 0;
81 }
m^2

2.O(mlogm)

既然不能暴力做最小生成树,那就用LCT维护最小生成树即可。

  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 #define R register
  5 #define inf 0x7fffffff
  6 #define maxn 100010
  7 #define maxm 200010
  8 struct ed{
  9     int a, b, w;
 10     inline bool operator < (const ed &that) const {return w < that.w;} 
 11 }e[maxm];
 12 struct node *null;
 13 struct node
 14 {
 15     node *ch[2], *fa, *pos;
 16     int val, mn;
 17     bool rev;
 18     inline bool type()
 19     {
 20         return fa -> ch[1] == this;
 21     }
 22     inline bool check()
 23     {
 24         return fa -> ch[type()] == this;
 25     }
 26     inline void pushup()
 27     {
 28         pos = this; mn = val;
 29         ch[0] -> mn < mn ? mn = ch[0] -> mn, pos = ch[0] -> pos : 0;
 30         ch[1] -> mn < mn ? mn = ch[1] -> mn, pos = ch[1] -> pos : 0;
 31     }
 32     inline void pushdown()
 33     {
 34         if (rev)
 35         {
 36             ch[0] -> rev ^= 1;
 37             ch[1] -> rev ^= 1;
 38             std::swap(ch[0], ch[1]);
 39             rev ^= 1;
 40         }
 41     }
 42     inline void pushdownall()
 43     {
 44         if (check()) fa -> pushdownall();
 45         pushdown();
 46     }
 47     inline void rotate()
 48     {
 49         R bool d = type(); R node *f = fa, *gf = f -> fa;
 50         (fa = gf, f -> check()) ? fa -> ch[f -> type()] = this : 0;
 51         (f -> ch[d] = ch[!d]) != null ? (ch[!d] -> fa = f) : 0;
 52         (ch[!d] = f) -> fa = this;
 53         f -> pushup();
 54     }
 55     inline void splay(R bool npda = 1)
 56     {
 57         if (npda) pushdownall();
 58         for (; check(); rotate())
 59             if (fa -> check())
 60             {
 61                 if (type() == fa -> type()) fa -> rotate();
 62                 else rotate();
 63             }
 64         pushup();
 65     }
 66     inline node *access()
 67     {
 68         R node *i = this, *j = null;
 69         for ( ; i != null; i = (j = i) -> fa)
 70         {
 71             i -> splay();
 72             i -> ch[1] = j;
 73             i -> pushup();
 74         }
 75         return j;
 76     }
 77     inline void make_root()
 78     {
 79         access(); splay(); rev ^= 1;
 80     }
 81     inline void link(R node *that)
 82     {
 83         make_root();
 84         fa = that;
 85         splay(0);
 86     }
 87     inline void cut(R node *that)
 88     {
 89         make_root();
 90         that -> access();
 91         that -> splay(0);
 92         that -> ch[0] = fa = null;
 93         that -> pushup();
 94     }
 95 }mem[1000010], *ncnt = mem, *edge = mem + 100010;
 96 int gcd(R int a, R int b)
 97 {
 98     return b ? gcd(b, a % b) : a;
 99 }
100 inline node *query(node *a, node *b)
101 {
102     a -> make_root();
103     b -> access(); b -> splay(0);
104     return b -> pos;
105 }
106 int Fa[maxn], m, n;
107 int Find(R int x) {return Fa[x] == x ? x : Fa[x] = Find(Fa[x]);}
108 int main()
109 {
110     null = mem;
111     *null = (node) {{null, null}, null, null, inf, inf, 0};
112     scanf("%d%d", &n, &m);
113     for (R int i = 1; i <= m; ++i) scanf("%d%d%d", &e[i].a, &e[i].b, &e[i].w);
114     R int s, t; scanf("%d%d", &s, &t);
115     std::sort(e + 1, e + m + 1);
116     R int up = 1, down = 0;
117     for (R int i = 1; i <= n; ++i)
118     {
119         Fa[i] = i;
120         mem[i] = (node) {{null, null}, null, null, inf, inf, 0};
121     }
122     R int con = 0;
123     for (R int i = 1; i <= m; ++i)
124     {
125         R int mi, a = e[i].a, b = e[i].b;
126         if (a == b) continue;
127         R int f1 = Find(a), f2 = Find(b);
128         *(edge + i) = (node) {{null, null}, null, null, e[i].w, e[i].w, 0};
129         if (f1 != f2)
130         {
131             Fa[f1] = f2;
132             (mem + a) -> link(edge + i);
133             (mem + b) -> link(edge + i);
134             ++con;
135         }
136         else
137         {
138             R node *p = query(mem + a, mem + b);
139             (mem + e[p - edge].a) -> cut(p);
140             (mem + e[p - edge].b) -> cut(p);
141             (mem + a) -> link(edge + i);
142             (mem + b) -> link(edge + i);
143         }
144         if (Find(s) == Find(t))
145         {
146             mi = query(mem + s, mem + t) -> val;
147             // 从s到t的链上最小值。
148             if (1ll * up * mi > 1ll * e[i].w * down)
149             {
150                 up = e[i].w;
151                 down = mi;
152             }
153         }
154     }
155     if (down == 0) puts("IMPOSSIBLE");
156     else if (up % down == 0) printf("%d\n", up / down);
157     else printf("%d/%d\n", up / gcd(up, down), down / gcd(up, down));
158     return 0;
159 }
mlogm

 

posted @ 2017-03-25 23:11  cot  阅读(55)  评论(0编辑  收藏