CF1037E Trips

題意

一共有\(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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章