標籤:問題 type ret href dig pac print 連結 color
[題目連結]
http://codeforces.com/problemset/problem/1037/E
[演算法]
首先離線 , 將問題倒過來考慮 , 轉化為 : 每次刪除一條邊 , 此時最多有多少人蔘加旅行
假設所有點都選取 , 那麼 ,如果一個點的度數 < k , 顯然這個點不能選 , 我們需要刪除它和所有與它相鄰的邊
顯然 , 所有的點和邊最多隻會被刪去一次 , 故時間複雜度為O(N + M)
[代碼]
#include<bits/stdc++.h>using namespace std;const int MAXN = 2e5 + 10;int n , m , k;int deg[MAXN],res[MAXN],x[MAXN],y[MAXN],q[MAXN];bool visited[MAXN],del[MAXN];vector< int > a[MAXN],b[MAXN];template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }template <typename T> inline void read(T &x){ T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - ‘0‘; x *= f;}int main(){ read(n); read(m); read(k); for (int i = 1; i <= m; i++) { read(x[i]); read(y[i]); a[x[i]].push_back(y[i]); a[y[i]].push_back(x[i]); b[x[i]].push_back(i); b[y[i]].push_back(i); deg[x[i]]++; deg[y[i]]++; } int l = 1 , r = 0 ,ans = n; for (int i = 1; i <= n; i++) { if (deg[i] < k) { visited[i] = true; q[++r] = i; ans--; } } for (int i = m; i >= 1; i--) { while (l <= r) { int u = q[l++]; for (unsigned j = 0; j < a[u].size(); j++) { if (!del[b[u][j]]) { deg[u]--; deg[a[u][j]]--; del[b[u][j]] = true; if (!visited[a[u][j]] && deg[a[u][j]] < k) { ans--; visited[a[u][j]] = true; q[++r] = a[u][j]; } } } } res[i] = ans; if (!del[i]) { del[i] = true; deg[x[i]]--; deg[y[i]]--; if (!visited[x[i]] && deg[x[i]] < k) { visited[x[i]] = true; ans--; q[++r] = x[i]; } if (!visited[y[i]] && deg[y[i]] < k) { visited[y[i]] = true; ans--; q[++r] = y[i]; } } } for (int i = 1; i <= m; i++) printf("%d\n",res[i]); return 0; }
[Codeforces 1037E] Trip