带权并查集
#include<bits/stdc++.h>
#define LL long long
#define PB push_back
using namespace std;
const int INF=0x3f3f3f3f;
const int N=1e6+10,M=N*400,mod=1e9+7;
int a[N];
int s[N][2];
int d[N];
int n,k;
int ans;
vector<int>G[N];
int typ[N];
int p[N];
int f(int x){
if(x==a[x])return x;
int y=a[x];
a[x]=f(a[x]);
d[x]=(d[x]+d[y])%2;
return a[x];
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%1d",&p[i]);
for(int i=1;i<=k;i++)a[i]=i,s[i][0]=1,typ[i]=-1;
ans=0;
for(int i=1,m,x;i<=k;i++){
scanf("%d",&m);
for(int j=1;j<=m;j++){
scanf("%d",&x);
G[x].PB(i);
}
}
for(int i=1,x,y,u,v;i<=n;i++){
if(G[i].size()==1){
x=G[i][0];
y=f(x);
if(typ[y]==-1){
ans-=min(s[y][0],s[y][1]);
if((d[x]+(!p[i]))%2)typ[y]=1,swap(s[y][0],s[y][1]),ans+=s[y][1];
else typ[y]=0,ans+=s[y][1];
}
}
else if(G[i].size()==2){
x=G[i][0],y=G[i][1];
u=f(x),v=f(y);
if(u!=v){
if(typ[u]==-1)ans-=min(s[u][0],s[u][1]);
else ans-=s[u][1];
if(typ[v]==-1)ans-=min(s[v][0],s[v][1]);
else ans-=s[v][1];
a[u]=v;
d[u]=(d[x]+d[y]+(!p[i]))%2;
if(typ[v]!=-1&&typ[u]==-1){
typ[u]=(typ[v]+d[u])%2;
if(typ[u]==1)swap(s[u][0],s[u][1]);
}
if(typ[u]!=-1&&typ[v]==-1){
typ[v]=(typ[u]+d[u])%2;
if(typ[v]==1)swap(s[v][0],s[v][1]);
}
if(typ[u]!=-1)s[v][0]+=s[u][0],s[v][1]+=s[u][1];
else s[v][0]+=s[u][d[u]],s[v][1]+=s[u][!d[u]];
if(typ[v]==-1)ans+=min(s[v][0],s[v][1]);
else ans+=s[v][1];
}
}
printf("%d\n",ans);
}
return 0;
}
/*
*/