【JZOJ4807】破解

description


analysis

  • 首先把[L,R][L,R][L,R]看成[L,R+1)[L,R+1)[L,R+1),然后把头尾相连的区间视作做操作

  • 就是说,如果一个大区间包含一个与它头或尾相连的小区间,就大区间视作拆成小区间和小区间的补集

  • 大区间完全包含另若干各区间(头尾不相连),两两没有影响

  • 对于搞完后大小为nnn的区间,该区间答案为2n−12^{n-1}2n1

  • 然后每个区间头和尾连起来,并查集做一做,求出一共有kkk个联通块

  • 如果原图有mmm个点,则最终答案就是∑i=1k2ni−1=2m−k\sum_{i=1}^{k}2^{{n_i}-1}=2^{m-k}i=1k2ni1=2mk

  • 这个并查集怎么搞自行思考


code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXN 10000005
#define MAXM 100005*2
#define mod 1000000007
#define ll long long
#define fo(i,a,b) for (ll i=a;i<=b;++i)
#define fd(i,a,b) for (ll i=a;i>=b;--i)

using namespace std;

ll fa[MAXM],f[MAXM];
bool bz[MAXN];
ll turn[MAXN];
ll n,m,T,tot,cnt;

inline ll read()
{
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline ll getfa(ll x)
{
	return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
inline void merge(ll x,ll y)
{
	ll xx=getfa(x),yy=getfa(y);
	if (xx==yy)return;fa[xx]=yy;
}
inline ll pow(ll x,ll y)
{
	ll z=1;
	while (y)
	{
		if (y&1)z=z*x%mod;
		x=x*x%mod,y>>=1;
	}
	return z;
}
int main()
{
	//freopen("T2.in","r",stdin);
	T=read();
	while (T--)
	{
		n=read(),m=read(),tot=cnt=0;
		fo(i,1,m*2)fa[i]=i;
		memset(bz,1,sizeof(bz));
		memset(turn,0,sizeof(turn));
		fo(i,1,m)
		{
			ll l=read(),r=read()+1;
			if (bz[l])bz[l]=0,f[++cnt]=l,turn[l]=cnt;
			if (bz[r])bz[r]=0,f[++cnt]=r,turn[r]=cnt;
			merge(turn[l],turn[r]);
		}
		memset(bz,1,sizeof(bz));
		fo(i,1,cnt)if (bz[getfa(i)])bz[getfa(i)]=0,++tot;
		printf("%lld\n",pow(2,cnt-tot));
	}
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值