专栏文章

题解:CF1037E Trips

CF1037E题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miope5vu
此快照首次捕获于
2025/12/02 22:58
3 个月前
此快照最后确认于
2025/12/02 22:58
3 个月前
查看原文

CF1037E

入手

先考虑将问题简化, 如果只要求一天晚上的人数怎么做?
答案:重复将所有度数小于 kk 的点去掉,并删除相邻的边,直到没有这样的点为止。
不难看出这是一个改版的拓扑排序。

解法

通过这样的方法,我们就可以先求出最后一天的旅行人数。
考虑从 mm 天到第 11 天倒着求,第 i1i-1 天就是在第 ii 天的基础上断一条边,会有点的度数减小,方便我们做拓扑。
每次删边的时候,将连接的两个点度数减一。

程序设计

拓扑排序需要简单修改
我这边删除边是邻接表硬删(第 5151 行)
我使用了函数 qingtui(x) 来删除一个点并加入拓扑的队列
CPP
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=2e5+10;
vector<int> to[N];
struct Edge{int u,v;}e[N];
int n,m,k,ans;
int d[N];// 度数
bool del[N];

queue<int> q;// 拓扑排序

void qingtui(int x){
    q.push(x);
    ans--;
    del[x]=1;
}

void topo(){
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int v:to[u]){
            if(!del[v] && (--d[v])<k){
                qingtui(v);
            }
        }
    }
}

signed main(){
	ios::sync_with_stdio(false); cin.tie(0);
	
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        e[i]={u,v};
        to[u].push_back(v);
        to[v].push_back(u);
    }
    for(int i=1;i<=m;i++)d[e[i].u]++, d[e[i].v]++;

    ans=n;
    for(int i=1;i<=n;i++)if(d[i]<k)qingtui(i);
    topo();
    vector<int> output;
    output.push_back(ans);
    for(int i=m;i>=2;i--){
        int u=e[i].u, v=e[i].v;
        to[u].pop_back(); to[v].pop_back();
        if(!(del[u]||del[v])){// 这条边还没被拓扑排序删除掉
            if((--d[u])<k)qingtui(u);
            if((--d[v])<k)qingtui(v);

            topo();
        }
        output.push_back(ans);
    }
    reverse(output.begin(),output.end());
    for(int x:output)cout<<x<<"\n";
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...