[BZOJ1050] [HAOI2006] 旅行comf (Kruskal, LCT)

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

HINT

Source

Solution

  首先把边按边权排序

  第一种方法:枚举第一条边是哪条,之后从这条边开始做$Kruskal$,直到$S$与$T$联通或所有边都用完

  因为最小生成树可以保证最大边权尽量小,所以在最小边权指定的情况下可以找到比值最小的情况,复杂度$O(m^2)$

  ($Kruskal$不好玩,我们来玩$LCT$吧)

  第二种方法:我们用$LCT$维护最小生成树,按顺序插入边,当新插入的边的两端已经在树上时,把边权最小的边断开,再把这条边插进去

  联通性什么的都挺好判断的不用我多说了吧,复杂度是$O(mlog^2n)$的

  (好像有一些细节没讲,算了不管啦)

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 struct edge
  4 {
  5     int u, v, w;
  6     bool operator< (const edge &rhs) const
  7     {
  8         return w < rhs.w;
  9     }
 10 }e[5555];
 11 struct LCT
 12 {
 13     int c[2], fa, rev, val, mn, mx;
 14     int& operator[] (int x)
 15     {
 16         return c[x];
 17     }
 18 }a[5555];
 19 int sta[5555], top;
 20  
 21 int gcd(int x, int y)
 22 {
 23     return y ? gcd(y, x % y) : x;
 24 }
 25  
 26 void push_up(int k)
 27 {
 28     int c0 = a[k][0], c1 = a[k][1];
 29     a[k].mn = a[k].val ? k : 0, a[k].mx = k;
 30     if(a[a[c0].mn].val && a[a[c0].mn].val < a[a[k].mn].val)
 31         a[k].mn = a[c0].mn;
 32     if(a[a[c0].mx].val > a[a[k].mx].val) a[k].mx = a[c0].mx;
 33     if(a[a[c1].mn].val && a[a[c1].mn].val < a[a[k].mn].val)
 34         a[k].mn = a[c1].mn;
 35     if(a[a[c1].mx].val > a[a[k].mx].val) a[k].mx = a[c1].mx;
 36 }
 37  
 38 void push_down(int k)
 39 {
 40     if(a[k].rev)
 41     {
 42         swap(a[k][0], a[k][1]), a[k].rev = 0;
 43         a[a[k][0]].rev ^= 1, a[a[k][1]].rev ^= 1;
 44     }
 45 }
 46  
 47 bool isroot(int x)
 48 {
 49     return a[a[x].fa][0] != x && a[a[x].fa][1] != x;
 50 }
 51  
 52 void rotate(int x)
 53 {
 54     int y = a[x].fa, z = a[y].fa, dy = a[y][1] == x;
 55     if(!isroot(y)) a[z][a[z][1] == y] = x;
 56     a[y][dy] = a[x][!dy], a[a[x][!dy]].fa = y;
 57     a[x][!dy] = y, a[y].fa = x, a[x].fa = z;
 58     push_up(y);
 59 }
 60  
 61 void splay(int x)
 62 {
 63     sta[top = 1] = x;
 64     for(int i = x; !isroot(i); i = a[i].fa)
 65         sta[++top] = a[i].fa;
 66     while(top)
 67         push_down(sta[top--]);
 68     while(!isroot(x))
 69     {
 70         int y = a[x].fa, z = a[y].fa;
 71         if(!isroot(y))
 72             if(a[y][1] == x ^ a[z][1] == y) rotate(x);
 73             else rotate(y);
 74         rotate(x);
 75     }
 76     push_up(x);
 77 }
 78  
 79 void access(int x)
 80 {
 81     for(int i = 0; x; x = a[x].fa)
 82         splay(x), a[x][1] = i, i = x;
 83 }
 84  
 85 void make_root(int x)
 86 {
 87     access(x), splay(x), a[x].rev ^= 1;
 88 }
 89  
 90 void link(int x, int y)
 91 {
 92     make_root(x), a[x].fa = y;
 93 }
 94  
 95 void cut(int x, int y)
 96 {
 97     make_root(x), access(y), splay(y);
 98     a[y][0] = a[x].fa = 0, push_up(y);
 99 }
100  
101 int find_root(int x)
102 {
103     access(x), splay(x);
104     while(a[x][0])
105         x = a[x][0];
106     return x;
107 }
108  
109 int main()
110 {
111     int n, m, u, v, sss, ttt, mx = 50000, mn = 1, tmp;
112     scanf("%d%d", &n, &m);
113     for(int i = 1; i <= m; ++i)
114     {
115         scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
116         if(e[i].u == e[i].v) --i, --m;
117     }
118     scanf("%d%d", &sss, &ttt);
119     sss += m, ttt += m;
120     sort(e + 1, e + m + 1);
121     a[0].val = 50000, a[0].mx = 5554;
122     for(int i = 1; i <= m + n; ++i)
123         a[i].val = e[i].w, push_up(i);
124     for(int i = 1; i <= m; ++i)
125     {
126         u = e[i].u + m, v = e[i].v + m;
127         if(find_root(u) == find_root(v))
128         {
129             make_root(u), access(v), splay(v);
130             tmp = a[v].mn;
131             cut(e[tmp].u + m, tmp);
132             cut(e[tmp].v + m, tmp);
133         }
134         link(u, i), link(v, i);
135         if(find_root(sss) != find_root(ttt)) continue;
136         make_root(sss), access(ttt), splay(ttt);
137         if(1.0 * a[a[ttt].mx].val / a[a[ttt].mn].val < 1.0 * mx / mn)
138             mx = a[a[ttt].mx].val, mn = a[a[ttt].mn].val;
139     }
140     tmp = gcd(mx, mn), mx /= tmp, mn /= tmp;
141     if(mx == 50000) puts("IMPOSSIBLE");
142     else if(mn == 1) printf("%d\n", mx);
143     else printf("%d/%d\n", mx, mn);
144     return 0;
145 }
View Code

 

posted @ 2016-07-13 17:40  CtrlCV  阅读(746)  评论(0编辑  收藏  举报