• 2020牛客多校第八场A-All Star Game


    https://ac.nowcoder.com/acm/contest/5673/A

    题意

    有n个篮球运动员,m个球迷。

    一个球迷可能是多个球员的粉丝

    选择最少的球员进全明星赛,使得所有球迷都愿意观看(至少一个球迷想看的球员入选)。

    想看的球员标准如下

    有q个粉丝关系的修改,修改完回答询问。(1 le n, m,q le 2*10^5)

    题解

    用map处理出每个粉丝关系存在的时间段,把这个粉丝关系作为一条边插入到这个时间段中,用线段树维护这个时间段,在进入这个时间段时,把只属于这个时间段的边加入关系。

    由于只要一个粉丝和另一个粉丝喜欢的球员有相同的,那么两个粉丝喜欢的球员会进行合并,所以我们要求的就是n个球员的联通分量个数,其中不包含鼓励球员的点

    我们使用可撤销并查集维护这个数量,具体做法是

    首先肯定不能路径压缩,我们选择直接按并查集大小合并,小的并查集向大的合并。

    我们一开始把答案设为m,即粉丝的数量

    设x为球员,y为球迷

    x,y加边的时候,如果本来不连通,且y原来有边,那么ans--

    x,y删边的时候,如果删完他们不连通,且y删完还有变,那么ans++

    把球迷的sz初始设为1,球员的sz初始设为0,那么直接用联通块的sz判断是否还有球员向球迷的边即可。

    但要注意,每个球迷都要有喜欢的球员,要维护并判断一下

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct READ {
        inline char read() {
        #ifdef _WIN32
            return getchar();
        #endif
            static const int IN_LEN = 1 << 18 | 1;
            static char buf[IN_LEN], *s, *t;
            return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
        }
        template <typename _Tp> inline READ & operator >> (_Tp&x) {
            static char c11, boo;
            for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
                if(c11 == -1) return *this;
                boo |= c11 == '-';
            }
            for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
            boo && (x = -x);
            return *this;
        }
    } in;
    
    const int N = 5e5 + 50;
    #define pii pair<int, int>
    map<pii, int> mp;
    pii edge[N<<1];
    int vis[N<<1];
    int link[N];
    int ans, num;
    
    
    
    int f[N], sz[N];
    stack<pii> s;
    int find(int x) { return x == f[x] ? x : find(f[x]); }
    int merge(int x, int y) {
        x = find(x); y = find(y);
        if (x == y) return 0;
        if (sz[x] < sz[y]) swap(x, y);
        sz[x] += sz[y];
        if (sz[x] >= 2 && sz[y]) ans--;
        f[y] = x;
        s.push(pii(x, y)); return 1;
    }
    void del(int len) {
        while (!s.empty() && (len--)) {
            int x = s.top().first, y = s.top().second;
            s.pop();
            if (sz[x] < sz[y]) swap(x, y);
            if (sz[x] >= 2 && sz[y]) ans++;
            sz[x] -= sz[y];
            f[y] = y;
        }
    }
    
    #define ls (o<<1)
    #define rs (o<<1|1)
    #define mid ((l+r)>>1)
    vector<int> t[N<<2];
    void update(int o, int l, int r, int ql, int qr, int id) {
        if (ql > qr) return;
        if (ql <= l && r <= qr) { t[o].push_back(id); return; }
        if (ql <= mid) update(ls, l, mid, ql, qr, id);
        if (qr > mid) update(rs, mid + 1, r, ql, qr, id);
    }
    void query(int o, int l, int r) {
        int len = 0;
        for (int id : t[o]) {
            link[edge[id].second]++;
            if (link[edge[id].second] == 1) num--;
            len += merge(edge[id].first, edge[id].second);
        }
        if (l == r) {
            if (num) puts("-1");
            else printf("%d
    ", ans);
            for (int id : t[o]) {
                link[edge[id].second]--;
                if (link[edge[id].second] == 0) num++;
            }
            del(len);
            return;
        }
        query(ls, l, mid); query(rs, mid + 1, r);
        for (int id : t[o]) {
            link[edge[id].second]--;
            if (link[edge[id].second] == 0) num++;
        }
        del(len);
    }
    int main() {
        int n, m, q; in >> n >> m >> q;
        int cnt = 0;
        num = ans = m;
        for (int i = 1; i <= n + m; i++) f[i] = i;
        for (int i = n + 1; i <= n + m; i++) sz[i] = 1;
        for (int i = 1; i <= n; i++) {
            int k; in >> k;
            for (int j = 1; j <= k; j++) {
                int x; in >> x; x += n;
                mp[pii(i, x)] = ++cnt;
                edge[cnt] = pii(i, x);
                vis[cnt] = 1;
            }
        }
        for (int i = 1; i <= q; i++) {
            int u, v; in >> v >> u; v += n;
            if (!mp.count(pii(u, v))) {
                mp[pii(u, v)] = ++cnt;
                edge[cnt] = pii(u, v);
            }
            int id = mp[pii(u, v)];
            if (!vis[id]) vis[id] = i;
            else {
                update(1, 1, q, vis[id], i - 1, id);
                vis[id] = 0;
            }
        }
        for (int i = 1; i <= cnt; i++) {
            if (vis[i]) update(1, 1, q, vis[i], q, i);
        }
        query(1, 1, q);
        return 0;
    }
    
  • 相关阅读:
    LeetCode "Super Ugly Number" !
    LeetCode "Count of Smaller Number After Self"
    LeetCode "Binary Tree Vertical Order"
    LeetCode "Sparse Matrix Multiplication"
    LeetCode "Minimum Height Tree" !!
    HackerRank "The Indian Job"
    HackerRank "Poisonous Plants"
    HackerRank "Kundu and Tree" !!
    LeetCode "Best Time to Buy and Sell Stock with Cooldown" !
    HackerRank "AND xor OR"
  • 原文地址:https://www.cnblogs.com/artoriax/p/13632519.html
Copyright © 2020-2023  润新知