【CF1037E】Trips

题目描述

There are \(n\) persons who initially don't know each other. On each morning, two of them, who were not friends before, become friends.

We want to plan a trip for every evening of \(m\) days. On each trip, you have to select a group of people that will go on the trip. For every person, one of the following should hold:

  • Either this person does not go on the trip,
  • Or at least \(k\) of his friends also go on the trip.

Note that the friendship is not transitive. That is, if \(a\) and \(b\) are friends and \(b\) and \(c\) are friends, it does not necessarily imply that \(a\) and \(c\) are friends.

For each day, find the maximum number of people that can go on the trip on that day.

输入输出格式

输入格式:

The first line contains three integers \(n\) , \(m\) , and \(k\) ($ 2≤n≤210^5,1≤m≤210^5 ,1≤k<n $) — the number of people, the number of days and the number of friends each person on the trip should have in the group.

The \(i -th\) ( \(1≤i≤m\) ) of the next \(m\) lines contains two integers \(x\) and \(y\) ( $1≤x,y≤n , x≠y $ ), meaning that persons \(x\)and \(y\) become friends on the morning of day \(i\) . It is guaranteed that \(x\) and \(y\) were not friends before.

输出格式:

Print exactly \(m\) lines, where the \(i -th\) of them ( \(1≤i≤m\) )contains the maximum number of people that can go on the trip on the evening of the day \(i\) .

输入输出样例

输入样例#1:

4 4 2
2 3
1 2
1 3
1 4

输出样例#1:

0
0
3
3

输入样例#2:

5 8 2
2 1
4 2
5 4
5 2
4 3
5 1
4 1
3 2

输出样例#2:

0
0
0
3
3
4
4
5

输入样例#3:

5 7 2
1 5
3 2
2 5
3 4
1 2
5 3
1 3

输出样例#3:

0
0
0
0
3
4
4

分析

考虑对朋友之间建边,这样便将问题转化为动态加边了。然后每天选出一些点,使这些点与其他被选的点有至少 \(k\) 条连边。但正着做不好做,于是考虑反着做。

我们先将所有的边都连上,如果这时点的度数小于 \(k\) ,那么这个点无论如何也不可能被选,所以我们直接将其删除,同时更新与其相邻的点。此时剩余的点即第 \(m\) 天的答案。

最后,倒着删边,统计答案即可。

代码

#include<set>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#define il inline
#define re register
#define maxn 200005
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;

template<typename T>inline void read(T &x){
    T f=1;x=0;char c;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=x*10+(c^48);
    x*=f;
}

struct edge{
    int u,v;
}e[maxn];

set<int>st[maxn];

int n,m,k,cnt;
int ans[maxn],du[maxn];
bool del[maxn];

void Delete(int x){
    if(du[x]>=k||del[x]) return;
    del[x]=1;cnt--;
    queue<int>q;
    q.push(x);
    while(!q.empty()){
        int now=q.front();
        q.pop();
        for(auto y : st[now]){
            du[y]--;
            if(du[y]<k&&!del[y]){
                q.push(y);
                del[y]=1;cnt--;
            }
        }
    }
}

int main(){
    int x,y;
    read(n),read(m),read(k);
    cnt=n;
    for(int i=1;i<=m;++i){
        read(x),read(y);
        e[i].u=x,e[i].v=y;
        du[x]++,du[y]++;
        st[x].insert(y),st[y].insert(x);
    }
    for(int i=1;i<=n;++i)
        Delete(i);
    ans[m]=cnt;
    for(int i=m;i;--i){
        x=e[i].u,y=e[i].v;
        if(!del[x]) du[y]--;
        if(!del[y]) du[x]--;
        st[x].erase(y),st[y].erase(x);
        Delete(x),Delete(y);
        ans[i-1]=cnt;
    }
    for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
    return 0;

猜你喜欢

转载自www.cnblogs.com/hlw1/p/11285346.html