【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;

转载于:https://www.cnblogs.com/hlw1/p/11285346.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值