CF1037E Trips(思维)

正难则反。动态加边比较难以维护,考虑倒着维护

先把全部边都添加的状态维护好,之后倒着删边。

对于每一次,如果有一个人他没有k个好友,那么他就永远不可能旅游,因此将他删除后,并且用一个队列来做因为他删除而导致的一系列后果。

那么还在的人是都可以去旅游的,因为他们都有k个好友

因此我们每次删一条边就把两端点做一遍上述操作,因为所有的影响都是由这两端点产生,所以我们做完了所有状态

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int st[N];
set<int> s[N];
int n,m,k;
struct node{
    int a,b;
}e[N];
int in[N];
int ans[N];
int cnt;
void solve(int u){
    if(in[u]>=k||st[u])
        return ;
    st[u]=1;
    cnt--;
    queue<int> q;
    q.push(u);
    while(q.size()){
        auto t=q.front();
        q.pop();
        for(auto x:s[t]){
            in[x]--;
            if(in[x]<k&&!st[x]){
                st[x]=1;
                q.push(x);
                cnt--;
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>k;
    int i;
    for(i=1;i<=m;i++){
        int a,b;
        cin>>a>>b;
        e[i]={a,b};
        in[a]++;
        in[b]++;
        s[a].insert(b);
        s[b].insert(a);
    }
    cnt=n;
    for(i=1;i<=n;i++){
        solve(i);
    }
    ans[m]=cnt;
    for(i=m;i>=1;i--){
        int a=e[i].a,b=e[i].b;
        if(!st[b]) in[a]--;
        if(!st[a]) in[b]--;
        s[b].erase(a),s[a].erase(b);
        solve(a);solve(b);
        ans[i-1]=cnt;
    }
    for(i=1;i<=m;i++){
        cout<<ans[i]<<endl;
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13772749.html