• CF1037E Trips


    题意

    一共有(n)个人,他们开始互不认识,而每天早上不认识的两个人会变成朋友。一共有(m)天,每天晚上有的人要去旅行,去旅行的人必须满足ta有至少(k)个朋友也去旅行
    求每天去旅行的最大人数

    题解

    首先考虑一个朴素暴力:
    对于每次询问,在原图上不断删点,直到没有点的度小于k。
    复杂度O(nm)

    然后有一个简单的优化方法,我们发现,随着边的增多,留下的点会不断变多。那么从后往前,随着边的减少,留下的点会不断减少,且之前就被淘汰的点在后续状态中不可能被保留。
    也就是说如果我们从后往前处理询问,每次处理出答案之后保留这个残余图,下次操作在残余图上操作,那么每个点最多被删除一次,每条边最多被遍历2次。
    用队列模拟一下,复杂度O(n + m)

    #include<bits/stdc++.h>
    using namespace std;
    #define R register int
    #define AC 200100
    #define ac 400100
    
    int n, m, k, rnt, head, tail;
    int Head[AC], date[ac], Next[ac], id[ac], tot;
    int ans[AC], in[AC], q[AC];
    bool vis[AC], z[AC];
    struct node{int x, y;}way[AC];
    
    inline int read()
    {
        int x = 0;char c = getchar();
        while(c > '9' || c < '0') c = getchar();
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x;
    }
    
    inline void upmin(int &a, int b) {if(b < a) a = b;}
    inline void upmax(int &a, int b) {if(b > a) a = b;}
    
    inline void add(int f, int w, int S)
    {
        date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, in[w] ++, id[tot] = S;
        date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot, in[f] ++, id[tot] = S;
    }
    
    void clear()
    {
        while(head < tail)
        {
            int x = q[++ head];
            -- rnt;
            for(R i = Head[x]; i; i = Next[i])
            {
                int now = id[i];
                if(vis[now]) continue;
                vis[now] = 1, -- in[way[now].x], -- in[way[now].y];
                if(!z[way[now].x] && in[way[now].x] < k) z[way[now].x] = 1, q[++ tail] = way[now].x;
                if(!z[way[now].y] && in[way[now].y] < k) z[way[now].y] = 1, q[++ tail] = way[now].y;
            }
        }
        head = tail = 0;
    }
    
    void pre()
    {
        n = read(), m = read(), k = read(), rnt = n;
        for(R i = 1; i <= m; i ++) 
            way[i].x = read(), way[i].y = read(), add(way[i].x, way[i].y, i);
    }
    
    void work()
    {
        for(R i = 1; i <= n; i ++) if(in[i] < k) q[++ tail] = i, z[i] = 1;
        clear(), ans[m] = rnt;
        for(R i = m; i; i --)
        {
            if(vis[i]) {ans[i - 1] = ans[i]; continue;}
            -- in[way[i].x], -- in[way[i].y], vis[i] = 1;
            if(!z[way[i].x] && in[way[i].x] < k) z[way[i].x] = 1, q[++ tail] = way[i].x;
            if(!z[way[i].y] && in[way[i].y] < k) z[way[i].y] = 1, q[++ tail] = way[i].y;
            clear(), ans[i - 1] = rnt;
        }
        for(R i = 1; i <= m; i ++) printf("%d
    ", ans[i]);
    }
    
    int main()
    {
    //	freopen("in.in", "r", stdin);
        pre();
        work();
    //	fclose(stdin);
        return 0;
    }
    
  • 相关阅读:
    数据结构2
    EF Fluent API
    VS2017+mysql5.7 连接数据库生成实体
    JavaScript中的枚举
    EasyUI datagird 排序 按数字类型的问题
    php 将秒数转换为时间(年、天、小时、分、秒)
    mySQL把秒转换成日期
    Android 界面间传参数
    android 登陆界面
    Android 在已有的项目上创建新的项目
  • 原文地址:https://www.cnblogs.com/ww3113306/p/10554300.html
Copyright © 2020-2023  润新知