zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    dom操作
    今天学到的知识点
    3.26随笔
    dom操作
    Ajax
    JSP、EL、JSTL
    Cookie和Session
    HttpServletResponse
    Servlet
    tomcat
  • 原文地址:https://www.cnblogs.com/artoriax/p/13632519.html
Copyright © 2011-2022 走看看