bzoj 3389
题意:给定1维连续T<= 1000000个点,以及n<=10000个线段,求最少的线段覆盖该区间。。
思路:很显然,贪心是可以做的。。不过这一题最有意思的是使可以转换为最短路模型。。
如果一条线段覆盖了[l, r],可以连l->r+1,距离为1的边。。
此外对于每个点i,连一条i->i-1,距离为0的边。。
那么实际上就是求1->n+1的最短路。。
感觉最短路模型还是很有意思的,跟2006北京赛区的最小割有点小像。。、
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef pair<int, int> pii; 4 const int maxn = 1001000; 5 struct edge{ 6 int v, w, next; 7 } e[maxn << 1]; 8 int dis[maxn], last[maxn], n, m, tot; 9 int use[maxn]; 10 11 inline void add(const int& u, const int& v, const int& w){ 12 e[tot] = (edge){v, w, last[u]}; last[u] = tot++; 13 } 14 15 void spfa(){ 16 priority_queue<pii, vector<pii>, greater<pii> > q; 17 for (int i = 1; i <= n + 1; ++i) dis[i] = 0x3fffffff; 18 pii tmp; 19 memset(use, 0, sizeof(int) * (n + 10)); 20 q.push( make_pair(0, 1) ), dis[1] = 0; 21 int u, v; 22 while (!q.empty()){ 23 u = q.top().second; q.pop(); 24 if (use[u]) continue; 25 use[u] = 1; 26 if (u == n+1) return; 27 for (int p = last[u]; p != -1; p = e[p].next){ 28 v = e[p].v; 29 if (dis[u] + e[p].w < dis[v]){ 30 dis[v] = dis[u] + e[p].w; 31 tmp.first = dis[v], tmp.second = v; 32 q.push(tmp); 33 } 34 } 35 } 36 } 37 38 void solve(){ 39 tot = 0; 40 memset(last, -1, sizeof(int) * (n + 10)); 41 int u, v; 42 for (int i = 0; i < m; ++i){ 43 scanf("%d%d", &u, &v); 44 add(u, v + 1, 1); 45 } 46 for (int i = 2; i <= n; ++i) 47 add(i, i-1, 0); 48 spfa(); 49 // for (int i = 1; i <= n; ++i) 50 // printf("", dis[1]); 51 int ans = dis[n+1]; 52 if (ans == 0x3fffffff) puts("-1"); 53 else cout << ans << endl; 54 } 55 56 int main(){ 57 // freopen("a.in", "r", stdin); 58 while (scanf("%d%d", &m, &n) != EOF){ 59 solve(); 60 } 61 }