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; }