当前位置: 代码迷 >> 综合 >> 2020牛客多校第八场A All-Star Game 线段树+可撤销并查集
  详细解决方案

2020牛客多校第八场A All-Star Game 线段树+可撤销并查集

热度:35   发布时间:2024-02-10 17:34:36.0

  1.球员编号从1-n,球迷编号从1-m,有重叠部分,可以将球迷编号整体加n.

  2.求最小球员个数等于求球迷的连通分量数,如果某个球迷的度为0表示没有喜欢的球员,此时无解输出-1.

  3.变量con表示度为0的球迷的数量,初始值为m,用来判断是否无解,变量ans表示球迷的连通分量数,初始值为m.

  4.先将初始状态直接存入map中,key为边,value为边存在的起始时间1.

  5.输入修改时,在map中查询是否有这条边,如果有表示此次为删边修改,向线段树插入这条边,插入区间为这条边的存活时间,最后从map中删除这条边.

  如果没有这条边就将其加入map中.

  6.输入结束后将map中剩余边插入线段树,插入区间即存活时间为该边加入map的时间到所有修改的结束时间Q.

  7.查询线段树遍历线段树的所有结点,进入结点时将该结点存储的所有边两端利用并查集合并,如果已经合并在一起了就不用修改,否则需要修改,同时con和ans值也要进行相应的更新,撤销时con和ans也要同时更新.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<stack>
using namespace std;
const int N=2e5+10;
typedef pair<int,int> pii;
struct node
{int x,y,rx,ry,fx,fy;node(int a,int b,int c,int d,int i,int j):x(a),y(b),rx(c),ry(d),fx(i),fy(j){}
};
map<pii,int>mp;
map<pii,int>::iterator it;
int Q,p[N*2],rk[N*2];
vector<pii>edge[N*4];
stack<node>st;
int deg[N*2];
int con,m,ans;
void add(int now,int l,int r,int x,int y,pii z)
{if(x<=l&&r<=y){edge[now].push_back(z);return;}int mid=(l+r)>>1;if(y<=mid)add(now<<1,l,mid,x,y,z);else if(x>mid)add(now<<1|1,mid+1,r,x,y,z);else{add(now<<1,l,mid,x,y,z);add(now<<1|1,mid+1,r,x,y,z);}
}
int find(int x)
{return p[x]==x?x:find(p[x]);}
void undo()
{node now=st.top();st.pop();p[now.y]=now.y;rk[now.x]=now.rx;deg[now.fy]--;deg[now.fx]--;if(deg[now.fx])ans++;if(!deg[now.fy])con++;
}
void query(int now,int l,int r)
{int tmp=0;for(int i=0;i<edge[now].size();++i){int x=find(edge[now][i].first),y=find(edge[now][i].second);int a=edge[now][i].first,b=edge[now][i].second;if(x==y)continue;tmp++;if(rk[x]<rk[y])swap(x,y);p[y]=x;st.push(node(x,y,rk[x],rk[y],a,b));if(rk[x]==rk[y])rk[x]++;if(deg[a])ans--;if(!deg[b])con--;deg[a]++;deg[b]++;}if(l==r){if(con) printf("-1\n");else printf("%d\n",ans);for(int i=0;i<tmp;++i)undo();return;}int mid=(l+r)>>1;query(now<<1,l,mid);query(now<<1|1,mid+1,r);for(int i=0;i<tmp;++i)undo();
}
int main()
{// freopen("1.txt","r",stdin);int n;cin>>n>>m>>Q;con=m;ans=m;for(int i=1;i<=n+m;++i)p[i]=i;for(int i=1;i<=n;++i){int k;scanf("%d",&k);while(k--){int y;scanf("%d",&y);y+=n;mp[{i,y}]=1;}}for(int i=1;i<=Q;++i){int x,y;scanf("%d%d",&x,&y);x+=n;pii tmp(y,x);it=mp.find(tmp);if(it==mp.end())mp[tmp]=i;else{if(it->second<=i-1)add(1,1,Q,it->second,i-1,tmp);mp.erase(it);}}for(it=mp.begin();it!=mp.end();++it)add(1,1,Q,it->second,Q,it->first);query(1,1,Q);return 0;
}