题目:
n个用户上网,有m条网线。每条网线规定只[L,R]区间中的用户能上,且最多同时上v人。问最多能同时几人在线。
组数不超过10
n,m(1<=n,m<=10000)
做法:
看这个题面,第一时间想到最大流。当然看到数据范围发现有点勉强。(但跑得还挺快)
考虑朴素的建图:
1、源点s和每个用户建边,流量1;
2、每个用户和能连上的网线建边,流量1;
3、每条网线和汇点t建边,流量v。
但是这样边数就太多了。想想,每条网线都要连R-L+1条边其实是没必要,考虑可以用线段树维护整段区间建边,这样可以减少很多的边。
然后用sap跑最大流。
代码:
#include <bits/stdc++.h> #define lson rt<<1 #define rson rt<<1|1 #define IOS ios::sync_with_stdio(false), cin.tie(0) #define debug(a) cout << #a ": " << a << endl using namespace std; typedef long long ll; inline int read(void){ char ch = getchar(); int ans = 0; while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) ans = ans*10 + ch-'0', ch = getchar(); return ans; } const int N = 7e4 + 7; const int M = 2e6 + 7; const int inf = 0x3f3f3f3f; int n, m; struct edge{ int v, cap, nxt; }e[M]; int tot, head[N]; int tag, T[N<<2]; int dep[N], gap[N], q[M], stk[M], top, tail, cur[N]; void init(void){ tot = 0; memset(head, -1, sizeof head); } void addedge(int u, int v, int f){ e[tot] = (edge){v, f, head[u]}; head[u] = tot++; e[tot] = (edge){u, 0, head[v]}; head[v] = tot++; } void build(int l, int r, int rt){ T[rt] = ++tag; if (l == r){ addedge(0, T[rt], 1); return; } int mid = (l+r) >> 1; build(l, mid, lson); build(mid+1, r, rson); addedge(T[lson], T[rt], mid-l+1); addedge(T[rson], T[rt], r-mid); } void update(int L, int R, int p, int l, int r, int rt){ if (L <= l && r <= R){ addedge(T[rt], p, r-l+1); return; } int mid = (l+r) >> 1; if (L <= mid) update(L, R, p, l, mid, lson); if (R > mid) update(L, R, p, mid+1, r, rson); } void bfs(int s, int t){ top = tail = 0; for (int i = s; i <= t; ++i){ dep[i] = -1, gap[i] = 0; } gap[0] = 1; dep[t] = 0; q[tail++] = t; while (top != tail){ int u = q[top++]; for (int i = head[u]; i != -1; i = e[i].nxt){ int v = e[i].v; if (dep[v] == -1){ dep[v] = dep[u]+1; gap[dep[v]]++; q[tail++] = v; } } } } int sap(int s, int t, int N){ bfs(s, t); for (int i = s; i <= t; ++i) cur[i] = head[i]; top = 0; int u = s; int ans = 0; while (dep[s] < N){ if (u == t){ int mn = inf; int inser; for (int i = 0; i < top; ++i){ if (mn > e[stk[i]].cap){ mn = e[stk[i]].cap; inser = i; } } for (int i = 0; i < top; ++i){ e[stk[i]].cap -= mn; e[stk[i]^1].cap += mn; } ans += mn; top = inser; u = e[stk[top]^1].v; continue; } bool flag = false; int v; for (int i = cur[u]; i != -1; i = e[i].nxt){ v = e[i].v; if (e[i].cap && dep[v]+1 == dep[u]){ flag = true; cur[u] = i; break; } } if (flag){ stk[top++] = cur[u]; u = v; continue; } int mn = N; for (int i = head[u]; i != -1; i = e[i].nxt){ if (e[i].cap && dep[e[i].v] < mn){ mn = dep[e[i].v]; cur[u] = i; } } gap[dep[u]]--; if (!gap[dep[u]]) return ans; dep[u] = mn + 1; gap[dep[u]]++; if (u != s) u = e[stk[--top]^1].v; } return ans; } int main(void){ while (scanf("%d%d", &n, &m) != EOF){ init(); tag = 0; build(1, n, 1); int s = 0, t = tag+m+1; for (int i = 1; i <= m; ++i){ int l = read(), r = read(), v = read(); update(l, r, tag+i, 1, n, 1); addedge(tag+i, t, v); } printf("%d\n", sap(s, t, t+1)); } return 0; }