題意
一共有\(n\)個人,他們開始互不認識,而每天早上不認識的兩個人會變成朋友。一共有\(m\)天,每天晚上有的人要去旅行,去旅行的人必須滿足ta有至少\(k\)個朋友也去旅行
求每天去旅行的最大人數
題解
首先考慮一個樸素暴力:
對於每次詢問,在原圖上不斷刪點,直到沒有點的度小於k。
複雜度O(nm)
然後有一個簡單的優化方法,我們發現,隨着邊的增多,留下的點會不斷變多。那麼從後往前,隨着邊的減少,留下的點會不斷減少,且之前就被淘汰的點在後續狀態中不可能被保留。
也就是說如果我們從後往前處理詢問,每次處理出答案之後保留這個殘餘圖,下次操作在殘餘圖上操作,那麼每個點最多被刪除一次,每條邊最多被遍歷2次。
用隊列模擬一下,複雜度O(n + m)
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 200100
#define ac 400100
int n, m, k, rnt, head, tail;
int Head[AC], date[ac], Next[ac], id[ac], tot;
int ans[AC], in[AC], q[AC];
bool vis[AC], z[AC];
struct node{int x, y;}way[AC];
inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}
inline void upmin(int &a, int b) {if(b < a) a = b;}
inline void upmax(int &a, int b) {if(b > a) a = b;}
inline void add(int f, int w, int S)
{
date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, in[w] ++, id[tot] = S;
date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot, in[f] ++, id[tot] = S;
}
void clear()
{
while(head < tail)
{
int x = q[++ head];
-- rnt;
for(R i = Head[x]; i; i = Next[i])
{
int now = id[i];
if(vis[now]) continue;
vis[now] = 1, -- in[way[now].x], -- in[way[now].y];
if(!z[way[now].x] && in[way[now].x] < k) z[way[now].x] = 1, q[++ tail] = way[now].x;
if(!z[way[now].y] && in[way[now].y] < k) z[way[now].y] = 1, q[++ tail] = way[now].y;
}
}
head = tail = 0;
}
void pre()
{
n = read(), m = read(), k = read(), rnt = n;
for(R i = 1; i <= m; i ++)
way[i].x = read(), way[i].y = read(), add(way[i].x, way[i].y, i);
}
void work()
{
for(R i = 1; i <= n; i ++) if(in[i] < k) q[++ tail] = i, z[i] = 1;
clear(), ans[m] = rnt;
for(R i = m; i; i --)
{
if(vis[i]) {ans[i - 1] = ans[i]; continue;}
-- in[way[i].x], -- in[way[i].y], vis[i] = 1;
if(!z[way[i].x] && in[way[i].x] < k) z[way[i].x] = 1, q[++ tail] = way[i].x;
if(!z[way[i].y] && in[way[i].y] < k) z[way[i].y] = 1, q[++ tail] = way[i].y;
clear(), ans[i - 1] = rnt;
}
for(R i = 1; i <= m; i ++) printf("%d\n", ans[i]);
}
int main()
{
// freopen("in.in", "r", stdin);
pre();
work();
// fclose(stdin);
return 0;
}