【思维题 并查集 图论】bzoj1576: [Usaco2009 Jan]安全路经Travel
有趣的思考题
Description
Input
* 第一行: 两个空格分开的数, N和M
* 第2..M+1行: 三个空格分开的数a_i, b_i,和t_i
Output
* 第1..N-1行: 第i行包含一个数:从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间.如果这样的路经不存在,输出-1.
题目分析
做法一
暴力树剖线段树
做法二
并查集[bzoj1576] [Usaco2009 Jan]安全路经Travel
1 #include<bits/stdc++.h> 2 const int maxn = 100035; 3 const int maxm = 400035; 4 5 int n,m,dis[maxn]; 6 struct cmp 7 { 8 bool operator ()(int a, int b) const 9 { 10 return dis[a] > dis[b]; 11 } 12 }; 13 struct Edge 14 { 15 int y,val; 16 Edge(int a=0, int b=0):y(a),val(b) {} 17 }edges[maxm]; 18 struct EdgeSv 19 { 20 int x,y,dis; 21 bool operator < (EdgeSv a) const 22 { 23 return dis < a.dis; 24 } 25 EdgeSv(int a=0, int b=0, int c=0):x(a),y(b),dis(c) {} 26 }edgeSv[maxm]; 27 int fa[maxn],fat[maxn],tag[maxn],dep[maxn]; 28 bool disVis[maxn],treeTag[maxm]; 29 int edgeTot,svTot,nxt[maxm],pre[maxm],head[maxn]; 30 std::priority_queue<int, std::vector<int>, cmp> q; 31 32 int read() 33 { 34 char ch = getchar(); 35 int num = 0; 36 bool fl = 0; 37 for (; !isdigit(ch); ch = getchar()) 38 if (ch=='-') fl = 1; 39 for (; isdigit(ch); ch = getchar()) 40 num = (num<<1)+(num<<3)+ch-48; 41 if (fl) num = -num; 42 return num; 43 } 44 void addedge(int u, int v) 45 { 46 int c = read(); 47 edges[++edgeTot] = Edge(v, c), nxt[edgeTot] = head[u], head[u] = edgeTot; 48 edges[++edgeTot] = Edge(u, c), nxt[edgeTot] = head[v], head[v] = edgeTot; 49 } 50 int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);} 51 int main() 52 { 53 memset(dis, 0x3f3f3f3f, sizeof dis); 54 memset(head, -1, sizeof head); 55 n = read(), m = read(); 56 for (int i=1; i<=n; i++) fa[i] = i; 57 for (int i=1; i<=m; i++) addedge(read(), read()); 58 dis[1] = 0, q.push(1); 59 while (q.size()) 60 { 61 int tt = q.top(); 62 q.pop(); 63 for (int i=head[tt]; i!=-1; i=nxt[i]) 64 if (dis[edges[i].y] > dis[tt]+edges[i].val){ 65 dis[edges[i].y] = dis[tt]+edges[i].val; 66 dep[edges[i].y] = dep[tt]+1, pre[edges[i].y] = i, fat[edges[i].y] = tt; 67 q.push(edges[i].y); 68 } 69 } 70 for (int i=2; i<=n; i++) treeTag[pre[i]] = 1; 71 for (int i=1; i<=edgeTot; i+=2) 72 if (!treeTag[i]&&!treeTag[i+1]){ 73 int u = edges[i].y, v = edges[i+1].y; 74 edgeSv[++svTot] = EdgeSv(u, v, edges[i].val+dis[u]+dis[v]); 75 } 76 std::sort(edgeSv+1, edgeSv+svTot+1); 77 for (int i=1; i<=svTot; i++) 78 { 79 int u = edgeSv[i].x, v = edgeSv[i].y, lstu = 0, lstv = 0; 80 int topu = get(u), topv = get(v); 81 while (topu!=topv) 82 { 83 if (dep[topu] < dep[topv]) 84 std::swap(u, v), std::swap(lstu, lstv), std::swap(topu, topv); 85 if (!tag[u]){ 86 tag[u] = i; 87 if (lstu) fa[lstu] = u; 88 }else if (lstu) fa[lstu] = topu; 89 lstu = topu, u = fat[topu], topu = get(u); 90 } 91 } 92 for (int i=2; i<=n; i++) 93 if (!tag[i]) puts("-1"); 94 else printf("%d\n",edgeSv[tag[i]].dis-dis[i]); 95 return 0; 96 }
END