A All-Star Game(维护连通分量大小,线段树+可撤回并查集)

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

题意:有n个球员m个粉丝,每个粉丝可以是若干个球员的粉丝,现要准备一场比赛,问最少安排多少个球员让所有粉丝都想看比赛(想看比赛得是有粉丝喜爱的球迷登场),还要提供询问操作:粉丝成为球员的粉丝,粉丝撤销成为球员的粉丝

分析:将粉丝开始成为球员粉丝到撤销成为球员粉丝定成一个时间区间,总共有q个询问时间大小就为q,这个q刚好可以表示上线段树上的n,那么处理输出就是在叶子节点进行操作,对于时间区间的处理用并查集维护其连通性,其中用栈记录曾经的相关值,在跳出这个时间区间的时候直接按出栈顺序返回恢复以前的值即可

#include<bits/stdc++.h>
using namespace std;
#define lson root<<1,l,midd
#define rson root<<1|1,midd+1,r
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define MP make_pair
typedef long long ll;
const ll INF=1e18;
const int M=5e5+6;
int Rank[M],fa[M],lst[M*10],red[M*10];
struct node{
    int u,v;
}e[M*10];
map<pii,int>mp;
vector<int>tr[M<<2];
int ans,sum,top,n,m,q,tot;
void update(int L,int R,int id,int root,int l,int r){
    if(L<=l&&r<=R){
        tr[root].pb(id);
        ///cout<<id<<"!!"<<endl;
        return;
    }
    int midd=(l+r)>>1;
    if(L<=midd)update(L,R,id,lson);
    if(R>midd)update(L,R,id,rson);
}
struct Node{
    int fau,fav,rku,rkv,sum,ans;
}sta[M*10];
int Find(int x){
    return x==fa[x]?x:Find(fa[x]);
}
void Union(int x,int y){
    top++;
    x=Find(x),y=Find(y);
    sta[top].fau=x,sta[top].fav=y;
    sta[top].rku=Rank[x],sta[top].rkv=Rank[y];
    sta[top].sum=sum,sta[top].ans=ans;
    if(x==y)return;
    if(x<=n&&y>n){///粉丝y没有偶像
        sum++;
        if(Rank[x]==1)///偶像x没有粉丝
            ans++;
    }
    else{
        if(Rank[x]!=1&&Rank[y]!=1)///粉丝z有偶像y,现在z喜欢的偶像x也原本有粉丝
            ans--;
    }
    if(Rank[x]<Rank[y])swap(x,y);
    if(Rank[x]==Rank[y])Rank[x]++;
    fa[y]=x;
}
///由于栈记录了之前步骤,所以依次撤销操作即可
void stapop(){
    fa[sta[top].fau]=sta[top].fau;
    fa[sta[top].fav]=sta[top].fav;
    Rank[sta[top].fau]=sta[top].rku;
    Rank[sta[top].fav]=sta[top].rkv;
    sum=sta[top].sum,ans=sta[top].ans;
    top--;
}
void query(int root,int l,int r){
    for(auto i:tr[root])
        Union(e[i].u,e[i].v);
    if(l==r){
        if(sum!=m)///没有所有粉丝都能看到
            puts("-1");
        else printf("%d\n",ans);
    }
    else{
        int midd=(l+r)>>1;
        query(lson);
        query(rson);
    }
    int len=tr[root].size();
    while(len--){
        stapop();
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&q);
    ///球员1~n,粉丝n+1~n+m
    for(int i=1;i<=n+m;i++){
        Rank[i]=1;
        fa[i]=i;
    }
    for(int i=1;i<=n;i++){
        int k;
        scanf("%d",&k);
        while(k--){
            int v;
            scanf("%d",&v),v+=n;
            if(!mp.count(MP(i,v))){
                mp[MP(i,v)]=++tot;
                e[tot]=node{i,v};
            }
            lst[tot]=1;
        }
    }
    for(int i=1;i<=q;i++){
        int u,v;
        scanf("%d%d",&v,&u);
        v+=n;
        if(!mp.count(MP(u,v))){
            mp[MP(u,v)]=++tot;
            e[tot]=node{u,v};
        }
        int id=mp[MP(u,v)];
        if(lst[id]==0)
            lst[id]=i;
        else{
            red[id]=i-1;
            if(i!=1)
                update(lst[id],red[id],id,1,1,q);
            lst[id]=red[id]=0;
        }
    }
    ///把到最后也没有消除的边人为地加上在q时刻结束
    for(int i=1;i<=tot;i++)
        if(lst[i]){
            red[i]=q;
            update(lst[i],red[i],i,1,1,q);
        }
    query(1,1,q);
    return 0;
}
View Code

 

posted @ 2020-08-20 22:21  starve_to_death  阅读(190)  评论(0编辑  收藏  举报