【JZOJ4807】破解
题目
分析
显而易见,当我们修改区间[1,3]、[1,2]时,其实就是修改了区间[2,3].。
那么我们对于区间[l,r],连一条l-1到r的无向边,
因为当修改[l,r]时,其实是修改l-1和l之间的空隙到r-1和r之间的空隙
然后又发现,在一个连通块,其中的点两两之间的区间都可以修改,
所以,将在同一联通快的点按先后顺序连成一条链,发现每一条边,答案就乘以2。
那么,答案就是2的边数次方。其实就是2的可以修改的点数减去联通块数次方。
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const long long mo=1000000007;
const int N=100005;
using namespace std;
int belong[N*2],last[N*2],next[N*2],to[N*2],n,_,m,t[10000005],b[N*2],tot,x[N],y[N],be;
int bj(int x,int y)
{
next[++tot]=last[x];
last[x]=tot;
to[tot]=y;
}
int dg(int x)
{
belong[x]=be;
for(int i=last[x];i;i=next[i])
{
if(!belong[to[i]])
{
dg(to[i]);
}
}
}
long long mi2(int y1)
{
long long sum=1,x=2;
while(y1)
{
if(y1&1) sum=sum*x%mo;
x=x*x%mo;
y1/=2;
}
return sum;
}
int main()
{
scanf("%d",&_);
while(_--)
{
scanf("%d%d",&n,&m);
memset(last,0,sizeof(last));
memset(next,0,sizeof(next));
memset(belong,0,sizeof(belong));
tot=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
b[i]=--x[i];
b[i+m]=y[i];
}
sort(b+1,b+1+m+m);
int k=0,p=-1000;
for(int i=1;i<=m+m;i++)
{
if(b[i]!=p)
{
p=b[i];
t[p]=++k;
}
}
for(int i=1;i<=m;i++)
{
bj(t[x[i]],t[y[i]]);
bj(t[y[i]],t[x[i]]);
}
be=0;
for(int i=1;i<=k;i++)
{
if(!belong[i])
{
be++;
dg(i);
}
}
printf("%lld\n",mi2(k-be));
for(int i=0;i<=m+m;i++)
t[b[i]]=0;
}
}