【图论】Codeforces Manthan Codefest18E Trips

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34454069/article/details/82346890

分析:

肥肠简单但却很容易想岔的题、、、(就是那种想清楚过后觉得水得不行,然而却想了半个小时的题)

首先,这题第一个坑,就是在线/离线

因为每次边是一条一条加的,这非常类似一些数据结构的特色(单一修改),所以很容易就去想在线怎么做。。。。然而我想了至少20分钟还是没个优秀的算法。。。所以就不得不考虑离线

首先要提及一点:这个题说要去的人数最大化,但其实每个人之间并没有矛盾关系,所以只要能去的人都去就行了,把这种人定义为“合法”。

加边改删边,发现这个题删边很容易实现:每次删除后,如果这两个点都是合法的,那么这两个点的度数都-1,再检查其剩下的度数是否比k小,如果是就把这个点删去,然后与它相连的点度数-1,如此递归地操作下去。

这样均摊下来的复杂度是 O ( n + m ) 的(每个点最多从“合法”变为“不合法”一次)。

现在问题转化为:求连完所有边后,哪些点合法?

这就是第二个坑点,如果你要检查是否合法,也是几乎不可行的。正确的姿势是:把所有度数小于k的点删去,和上面的操作几乎一模一样。这样一来,剩下的图中,每个点连的边都一定是合法的,并且度数都不小于k。所以就得到最终状态下(连完所有边后)的合法情况了。

代码是博主在考场上写的,略丑

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define SF scanf
#define PF printf
#define MAXN 200010
using namespace std;
typedef long long ll;
int n,m,k;
vector<int> a[MAXN],used[MAXN];
pair<int,int> l[MAXN];
set<pair<int,int> > st;
int d[MAXN];
bool del[MAXN];
int ansx[MAXN],ans;
void dele(int x){
    del[x]=1;
    ans--;
    for(int i=0;i<a[x].size();i++){
        int u=x,v=a[x][i];
        if(u>v)
            swap(u,v);
        if(del[a[x][i]]==0&&st.count(make_pair(u,v))==0){
            st.insert(make_pair(u,v));
            d[a[x][i]]--;
            if(d[a[x][i]]<k){
                dele(a[x][i]);
            }
        }
    }
}
int main(){
    SF("%d%d%d",&n,&m,&k);
    int u,v;
    for(int i=1;i<=m;i++){
        SF("%d%d",&u,&v);
        a[u].push_back(v);
        a[v].push_back(u);
        d[u]++;
        d[v]++;
        l[i]=make_pair(u,v);
    }
    ans=n;
    for(int i=1;i<=n;i++)
        if(d[i]<k&&del[i]==0)
            dele(i);
    for(int i=1;i<=n;i++)
        a[i].clear();
    st.clear();
    for(int i=1;i<=m;i++)
        if(del[l[i].first]==0&&del[l[i].second]==0){
            a[l[i].first].push_back(l[i].second);
            a[l[i].second].push_back(l[i].first);
        }
    for(int i=1;i<=n;i++)
        d[i]=a[i].size();
    for(int i=m;i>=1;i--){
        ansx[i]=ans;

        if(del[l[i].first]==0&&del[l[i].second]==0&&st.count(make_pair(min(l[i].first,l[i].second),max(l[i].first,l[i].second)))==0){

            st.insert(make_pair(min(l[i].first,l[i].second),max(l[i].first,l[i].second)));
            if(d[l[i].first]>d[l[i].second])
                swap(l[i].first,l[i].second);
            d[l[i].first]--;
            d[l[i].second]--;
            if(d[l[i].first]<k)
                dele(l[i].first);
            if(d[l[i].second]<k&&del[l[i].second]==0)
                dele(l[i].second);
        }
    }
    for(int i=1;i<=m;i++)
        PF("%d\n",ansx[i]);
} 

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/82346890