【Codeforces 1290】C Prefix Enlightenment(带权并查集)

传送门

ldxldx抓来看题
然后还没看完ldxldx就切掉了把我喊去看DD
结果还没看完就地震了

首先任意三个集合交为空
那么任意一个元素最多出现在两个集合内
考虑把集合看做点,元素看做边
那么实际上实际上就是给图黑白染色
每个边要求两边同/异色
用带权并查集维护同异色个数即可

对于只出现在一个集合的元素特殊处理即可

#include<bits/stdc++.h>
using namespace std;
#define re register
#define cs const
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
inline void readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=600005;
int n,k;
ll ans;
int fa[N],kd[N];
ll same[N],dif[N];
vector<int> lnk[N];
inline pii find(int x){
	if(x==fa[x])return pii(x,0);
	pii now=find(fa[x]);
	fa[x]=now.fi,kd[x]^=now.se;
	return pii(fa[x],kd[x]);
}
inline void merge(int u,int v,int tp){
	pii v1=find(u),v2=find(v);tp^=v1.se,tp^=v2.se;
	int f1=v1.fi,f2=v2.fi;
	if(f1==f2)return;
	ans-=min(same[f1],dif[f1]),ans-=min(same[f2],dif[f2]);
	if(tp)same[f1]+=dif[f2],dif[f1]+=same[f2],kd[f2]=1;
	else same[f1]+=same[f2],dif[f1]+=dif[f2],kd[f2]=0;
	ans+=min(same[f1],dif[f1]),fa[f2]=f1;
}
inline void calc(int u,int tp){
	pii x=find(u);
	ans-=min(same[x.fi],dif[x.fi]);
	if(tp^x.se)dif[x.fi]+=1e9;
	else same[x.fi]+=1e9;
	ans+=min(same[x.fi],dif[x.fi]);
}
char a[N];
signed main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read(),k=read();
	readstring(a);
	for(int i=1;i<=k;i++){
		fa[i]=i,same[i]=1,dif[i]=0,kd[i]=0;
		int m=read();
		while(m--)lnk[read()].pb(i);
	}
	for(int i=1;i<=n;i++){
		if(lnk[i].size()==1) calc(lnk[i][0],a[i]=='0');
		if(lnk[i].size()==2) merge(lnk[i][0],lnk[i][1],a[i]=='0');
		cout<<ans<<'\n';
	}
}

posted @ 2020-02-03 13:30  Stargazer_cykoi  阅读(138)  评论(0编辑  收藏  举报