【JZOJ4807】破解
Description
给出
M
个区间
Solution
结论1:每个区间至多取一次。
结论2:某些区间操作后的串会与另外一些区间操作的相同,那么只用保留某几个区间(我们称它们是有用的区间)。
那么我们现在要从许多区间中找到一些有用的区间。
我们对于区间
[l,r]
考虑从
l
连一条双向边到
设它为
n
,那么他们能组成的个数有:
离散化+dfs即可。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 500001
#define M 1000001
#define moh 400007
#define mo 1000000007
#define ll long long
using namespace std;
int to[M],next[M],last[M],num=0;
int h[moh],hh[moh];
bool bz[N];
int tt[N];
int get(int x)
{
int p=x%moh;
while(h[p] && h[p]!=x) p=(p+1)%moh;
h[p]=x;
hh[p]++;
return p;
}
bool check(int x)
{
int p=x%moh;
while(h[p] && h[p]!=x) p=(p+1)%moh;
if(h[p]==x && hh[p]>1) return true;
return false;
}
void link(int x,int y)
{
num++;
to[num]=y;
next[num]=last[x];
last[x]=num;
}
ll pow(int n)
{
ll b=1;
ll m=2;
while(n)
{
if(n%2) b=b*m%mo;
n/=2;
m=m*m%mo;
}
return b;
}
void dfs(int x)
{
bz[x]=1;
for(int i=last[x];i;i=next[i])
{
int v=to[i];
if(!bz[v]) dfs(v);
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
num=0;
memset(last,0,sizeof(last));
memset(bz,0,sizeof(bz));
memset(h,0,sizeof(h));
memset(hh,0,sizeof(hh));
int n,m;
scanf("%d %d",&n,&m);
tt[0]=0;
fo(i,1,m)
{
int l,r;
scanf("%d %d",&l,&r);
r++;
int x=get(l),y=get(r);
if(!check(l)) tt[++tt[0]]=x;
if(!check(r)) tt[++tt[0]]=y;
link(x,y);
link(y,x);
}
int q=tt[0];
fo(i,1,tt[0])
if(!bz[tt[i]])
{
dfs(tt[i]);
q--;
}
printf("%lld\n",pow(q));
}
}