洛谷P3295萌萌哒

题面

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#define mod 1000000007
using namespace std;
const int maxn = 1000007;
typedef long long ll;

ll f[maxn*10],st[maxn][25],position[maxn*10];
ll n,m,cnt;
int find(int x){return (f[x]==x)?x:f[x]=find(f[x]);}

void merge(int p1,int p2,int mi)
{
	int f1=find(st[p1][mi]),f2=find(st[p2][mi]);
	f[max(f1,f2)]=min(f1,f2);  //   根据预处理的顺序来定,因为下面分裂区间要使用 
	return ; 				   //   这里必须大的连小的 
}


int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)  //   并查集正常预处理 
	{
		for(int j=0;j<=log2(n)+1;j++)
		{
			st[i][j]=++cnt;
			position[cnt]=i;
			f[cnt]=cnt;
		}
	}
	
	for(int i=1;i<=m;i++)      //  区间拆解 ,个人理解为后面st表的前提,详情见st预处理 
	{
		int l1,l2,r1,r2;
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		for(int j=log2(n)+1;j>=0;j--)   //LCA  渐进法
		{
			if(l1+(1<<j)-1<=r1)   //   l1 l2 r1 r2同步  只判断一个就可以
			{
				merge(l1,l2,j);  //  可理解为当前位置点的严格合并前提,在此之后可以通过分裂 
				l1+=(1<<j);         //  统计底层所需数据,达成查找目的 
				l2+=(1<<j);
			}
		}
	}
	
	for(int j=log2(n)+1;j>=1;j--)  // j只能到1 因为会向下裂一步
	{
		for(int i=1;i+(1<<j)-1<=n;i++)
		{
			int fa=find(f[st[i][j]]),pp=position[fa]; // 如果没有经过上面那个循环的话,就变成了自己和自己相等 
			merge(i,pp,j-1);					// 不损伤答案 
			merge(i+(1<<(j-1)),pp+(1<<(j-1)),j-1);	// 合并		
		}
	} 
	long long ans=9;
	for(int i=2;i<=n;i++)// 第一位不可以选十个,所以ans起始为9   
	{
		if(f[st[i][0]]==st[i][0])
		{
			ans*=10;
			ans%=mod;
		}
	}
	cout<<ans%mod;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值