因为一个 (x_i) 不会出现超过两次,因此将有相同 (x_i) 的表达式之间连边,得到的图为若干链和环。
设 (f_{i,0/1,0/1,0/1}) 为考虑了链或环的前 (i) 个点,第一个点的状态,上一个变量的状态,现在的异或和状态的方案数,分类讨论来转移,最后将所有连通块的信息合并。
要注意处理自环和孤立点的情况。
#include<bits/stdc++.h>
#define maxn 200010
#define p 1000000007
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,m,tot;
int bel[maxn],deg[maxn];
ll f[maxn][2][2][2],g[maxn][2],h[maxn][2];
bool vis[maxn];
struct node
{
int k;
int v[2];
}a[maxn];
struct edge
{
int to,nxt,v;
}e[maxn];
int head[maxn],edge_cnt=1;
void add(int from,int to,int val)
{
e[++edge_cnt]={to,head[from],val},head[from]=edge_cnt;
e[++edge_cnt]={from,head[to],val},head[to]=edge_cnt;
deg[from]++,deg[to]++;
}
void dfs(int x,int link)
{
if(!link)
{
f[x][0][0][0]=1;
f[x][1][1][0]=a[x].k==2;
}
vis[x]=true;
int cnt=0;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(cnt==1) break;
if(i==link||(i^1)==link) continue;
cnt++;
bool flag;
for(int j=0;j<a[x].k;++j)
for(int k=0;k<a[y].k;++k)
if(abs(a[x].v[j])==abs(a[y].v[k])&&abs(a[x].v[j])==e[i].v)
flag=(a[x].v[j]==-a[y].v[k]);
if(vis[y])
{
if(!flag)
{
g[tot][0]=(f[x][0][0][0]+f[x][0][1][1]+f[x][1][0][1]+f[x][1][1][1])%p;
g[tot][1]=(f[x][0][1][0]+f[x][0][0][1]+f[x][1][0][0]+f[x][1][1][0])%p;
}
else
{
g[tot][0]=(f[x][0][1][1]+f[x][1][0][0]+f[x][0][0][1]+f[x][1][1][1])%p;
g[tot][1]=(f[x][0][0][0]+f[x][0][1][0]+f[x][1][1][0]+f[x][1][0][1])%p;
}
}
else
{
if(!flag)
{
for(int j=0;j<=1;++j)
{
f[y][j][1][1]=(f[y][j][1][1]+f[x][j][0][0])%p;
f[y][j][0][0]=(f[y][j][0][0]+f[x][j][0][0])%p;
f[y][j][1][1]=(f[y][j][1][1]+f[x][j][1][0])%p;
f[y][j][0][1]=(f[y][j][0][1]+f[x][j][1][0])%p;
f[y][j][1][0]=(f[y][j][1][0]+f[x][j][0][1])%p;
f[y][j][0][1]=(f[y][j][0][1]+f[x][j][0][1])%p;
f[y][j][1][0]=(f[y][j][1][0]+f[x][j][1][1])%p;
f[y][j][0][0]=(f[y][j][0][0]+f[x][j][1][1])%p;
}
}
else
{
for(int j=0;j<=1;++j)
{
f[y][j][0][1]=(f[y][j][0][1]+f[x][j][0][0])%p;
f[y][j][1][0]=(f[y][j][1][0]+f[x][j][0][0])%p;
f[y][j][1][1]=(f[y][j][1][1]+f[x][j][1][0])%p;
f[y][j][0][1]=(f[y][j][0][1]+f[x][j][1][0])%p;
f[y][j][1][1]=(f[y][j][1][1]+f[x][j][0][1])%p;
f[y][j][0][0]=(f[y][j][0][0]+f[x][j][0][1])%p;
f[y][j][1][0]=(f[y][j][1][0]+f[x][j][1][1])%p;
f[y][j][0][0]=(f[y][j][0][0]+f[x][j][1][1])%p;
}
}
dfs(y,i);
}
}
if(!cnt)
{
if(a[x].k==1)
{
g[tot][0]=(f[x][0][1][1]+f[x][0][0][0]+f[x][1][0][0]+f[x][1][1][1])%p;
g[tot][1]=(f[x][0][0][1]+f[x][0][1][0]+f[x][1][0][1]+f[x][1][1][0])%p;
}
else
{
g[tot][0]=(f[x][0][0][1]+f[x][0][1][1]+f[x][1][0][1]+f[x][1][1][1]+f[x][0][0][0]+f[x][0][1][1]+f[x][1][0][0]+f[x][1][1][1])%p;
g[tot][1]=(f[x][0][0][0]+f[x][0][1][0]+f[x][1][0][0]+f[x][1][1][0]+f[x][0][0][1]+f[x][0][1][0]+f[x][1][0][1]+f[x][1][1][0])%p;
}
}
}
int main()
{
read(n),read(m);
for(int i=1;i<=n;++i)
{
read(a[i].k);
for(int j=0;j<a[i].k;++j)
{
read(a[i].v[j]);
int id=abs(a[i].v[j]);
if(!bel[id]) bel[id]=i;
else
{
if(i!=bel[id]) add(i,bel[id],id);
else
{
vis[i]=true,tot++;
if(a[i].v[0]==a[i].v[1]) g[tot][0]=g[tot][1]=1;
else g[tot][1]=2;
}
bel[id]=-1;
}
}
}
for(int i=1;i<=m;++i)
{
if(a[bel[i]].k!=1) continue;
vis[bel[i]]=true,tot++,g[tot][0]=g[tot][1]=1;
}
for(int i=1;i<=n;++i)
if(!vis[i]&°[i]==1)
tot++,dfs(i,0);
for(int i=1;i<=n;++i)
if(!vis[i])
tot++,dfs(i,0);
h[0][0]=1;
for(int i=1;i<=tot;++i)
{
h[i][0]=(h[i-1][0]*g[i][0]%p+h[i-1][1]*g[i][1]%p)%p;
h[i][1]=(h[i-1][0]*g[i][1]%p+h[i-1][1]*g[i][0]%p)%p;
}
for(int i=1;i<=m;++i)
if(!bel[i])
h[tot][1]=h[tot][1]*2%p;
printf("%lld",h[tot][1]);
return 0;
}