歌名 - 歌手
0:00

    【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;
    	}
    }
    
    
    posted @ 2018-05-20 22:49  无尽的蓝黄  阅读(144)  评论(0编辑  收藏  举报