All-Star Game【LCT维护最大权生成树】

题目链接


  题意:有N个球员,还有M个球迷,然后有:

这是球迷去看球员比赛的条件,然后现在问最少多少个球员,就可以使得所有的球员都可以去看球赛。

  然后有Q次操作,会使得球迷x和球员y的关系进行转换,如果球迷x原本喜欢y现在就不喜欢了,如果原本不喜欢,现在就喜欢了。

  好了,我们可以发现这Q次操作,实际上就是保证了原来存在的边,现在把它删除;原来不存在的边,现在把它加进去。于是,再分析,我们可以发现,我们实际上要求的是有关M个球迷的合法联通块的个数(一定要有一个球员的联通块)。

  于是,不难发现,我们实际上就是求森林里树的个数了,如何维护森林中树的联通性呢?我想到的是LCT来进行维护,但是又有删除边的操作,而且有可能会形成环,所以我们需要进行进一步的贪心了。

  如果说我们现在要放入一条边,那么相当于可能要删除环中的一条边才可以,这该如何是好?我们肯定要贪婪的让最晚删除的边尽可能的保留在树中间,那么也就是我们可以想办法维护一个树的最早删除的边,令最早删除的边尽可能的晚岂不是就可以解决这个问题了,所以我们不妨对所有的边都离线存储下来,删除和加入操作也存储下来,然后我们判断每条边的删除时间,然后我们在生成树中维护最小删除时间,就可以维护这棵树的联通信息了,所以,我们实际上处理的就是最大权生成树了。

  于是,这道题就解决了,我们可以维护一棵LCT树,然后处理一下联通关系,那么每次操作的答案就是:联通块个数-自由的球员个数;如果有存在自由球迷,也就是没有喜欢的球员的,那么答案就是-1。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define Min_3(a, b, c) min(min(a, b), c)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 11e5 + 7;
int N, M, Q, all_num;
struct LinK_Cut_Tree
{
    int c[maxN][2], r[maxN], fa[maxN], s[maxN], w[maxN];
    inline bool isroot(int x) { return c[fa[x]][0] ^ x && c[fa[x]][1] ^ x; }
    inline void pushr(int x) { swap(c[x][0], c[x][1]); r[x] ^= 1; }
    inline void pushup(int x) { s[x] = Min_3(s[c[x][0]], s[c[x][1]], w[x]); }
    void pushdown(int x)
    {
        if(r[x])
        {
            if(c[x][0]) pushr(c[x][0]);
            if(c[x][1]) pushr(c[x][1]);
            r[x] = 0;
        }
    }
    void Rotate(int x)
    {
        int y = fa[x], z = fa[y], k = c[y][1] == x;
        if(!isroot(y)) c[z][c[z][1] == y] = x;
        fa[x] = z;
        c[y][k] = c[x][k ^ 1];
        fa[c[x][k ^ 1]] = y;
        c[x][k ^ 1] = y;
        fa[y] = x;
        pushup(y);
        pushup(x);
    }
    int Stap[maxN];
    void Splay(int x)
    {
        int y = x, z = 0;
        Stap[++z] = y;
        while(!isroot(y)) Stap[++z] = y = fa[y];
        while(z) pushdown(Stap[z--]);
        while(!isroot(x))
        {
            y = fa[x]; z = fa[y];
            if(!isroot(y)) (c[z][0] == y) ^ (c[y][0] == x) ? Rotate(x) : Rotate(y);
            Rotate(x);
        }
    }
    void access(int x)
    {
        int y = 0;
        while(x)
        {
            Splay(x);
            c[x][1] = y;
            pushup(x);
            y = x; x = fa[x];
        }
    }
    void makeroot(int x)
    {
        access(x);
        Splay(x);
        pushr(x);
    }
    int findroot(int x)
    {
        access(x);
        Splay(x);
        while(c[x][0]) { pushdown(x); x = c[x][0]; }
        Splay(x);
        return x;
    }
    bool link(int x, int y)
    {
        makeroot(x);
        if(findroot(y) != x)
        {
            fa[x] = y;
            return true;
        }
        return false;
    }
    void split(int x, int y)
    {
        makeroot(x);
        access(y);
        Splay(y);
    }
    void cut(int x, int y)
    {
        makeroot(x);
        if(findroot(y) != x || fa[y] != x || c[y][0]) return;
        fa[y] = c[x][1] = 0;
        pushup(x);
    }
    bool live_with(int x, int y)
    {
        makeroot(x);
        return findroot(y) == x;
    }
    inline void clear()
    {
        s[0] = INF;
        for(int i=1; i<=N; i++)
        {
            r[i] = 0; fa[i] = 0; s[i] = w[i] = INF;
            c[i][0] = c[i][1] = 0;
        }
    }
} lct;
int k[200005], mk[200005] = {0}, free_M, free_N;
struct Question
{
    int op, u, v, id;
    Question(int a=0, int b=0, int c=0, int d=0):op(a), u(b), v(c), id(d) {}
};
vector<Question> ques;
#define MP(a, b) make_pair(a, b)
map<pair<int, int>, bool> state;
map<pair<int, int>, int> mp;
pair<int, int> del[maxN];
bool use_edge[maxN] = {false};
int ans[200005], rid[maxN];
int main()
{
    lct.s[0] = lct.w[0] = INF; //init LCT
    scanf("%d%d%d", &N, &M, &Q);
    for(int i=1; i<=N + M; i++) lct.w[i] = INF;
    all_num = N + M; free_M = M; free_N = N;
    for(int i=1, x; i<=N; i++)
    {
        scanf("%d", &k[i]);
        for(int j=0; j<k[i]; j++)
        {
            scanf("%d", &x);
            ques.push_back(Question(1, i, N + x, 0));
            state[MP(i, N + x)] = true;
        }
        k[i] = 0;
    }
    for(int i=1, f, p; i<=Q; i++)
    {
        scanf("%d%d", &f, &p);
        f += N;
        if(state[MP(p, f)])
        {
            ques.push_back(Question(0, p, f, i));
            state.erase(MP(p, f));
        }
        else
        {
            ques.push_back(Question(1, p, f, i));
            state[MP(p, f)] = true;
        }
    }
    int len = (int)ques.size();
    for(int i=len - 1, f, p, tim; i>=0; i--)
    {
        p = ques[i].u;
        f = ques[i].v;
        if(ques[i].op)  //add
        {
            if(mp[MP(p, f)])
            {
                tim = mp[MP(p, f)];
                lct.w[N + M + i + 1] = tim;
                rid[tim] = i;
                mp.erase(MP(p, f));
            }
            else
            {
                tim = INF;
                lct.w[N + M + i + 1] = tim;
            }
        }
        else    //del
        {
            mp[MP(p, f)] = i;
            del[i] = MP(p, f);
        }
    }
    for(int i=0, u, v, m, ou, ov, om; i<len; i++)
    {
        u = ques[i].u; v = ques[i].v; m = N + M + i + 1;
        if(ques[i].op)  //add
        {
            if(lct.live_with(u, v))
            {
                lct.split(u, v);
                if(lct.s[v] < lct.w[m])
                {
                    ou = del[lct.s[v]].first;
                    ov = del[lct.s[v]].second;
                    om = rid[lct.s[v]] + N + M + 1;
                    use_edge[lct.s[v]] = false;
                    lct.cut(ou, om);
                    lct.cut(ov, om);
                    k[ou]--;
                    mk[ov - N]--;
                    lct.link(u, m);
                    lct.link(v, m);
                    k[u]++;
                    mk[v - N]++;
                    if(lct.w[m] < INF) use_edge[lct.w[m]] = true;
                }
            }
            else
            {
                lct.link(u, m);
                lct.link(v, m);
                k[u]++;
                mk[v - N]++;
                all_num--;
                if(mk[v - N] == 1) free_M--;
                if(k[u] == 1) free_N--;
                if(lct.w[m] < INF) use_edge[lct.w[m]] = true;
            }
        }
        else    //del
        {
            if(!use_edge[i])
            {
                ans[ques[i].id] = all_num - free_N;
                if(free_M) ans[ques[i].id] = -1;
                continue;
            }
            m = N + M + 1 + rid[i];
            lct.cut(u, m);
            lct.cut(v, m);
            k[u]--;
            mk[v - N]--;
            all_num++;
            if(!mk[v - N]) free_M++;
            if(!k[u]) free_N++;
        }
        ans[ques[i].id] = all_num - free_N;
        if(free_M) ans[ques[i].id] = -1;
    }
    for(int i=1; i<=Q; i++) printf("%d\n", ans[i]);
    return 0;
}
/*
3 3 5
3 1 2 3
0
2 2 3
2 2
2 2
2 1
2 3
2 2
ans:
1
1
1
-1
2
*/

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/107781194
今日推荐