一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条
件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2...S
r2完全相同。比如n=6时,某限制条件l1=1,r1=3,l2=4,r2=6,那么123123,351351均满足条件,但是12012,13
1141不满足条件,前者数的长度不为6,后者第二位与第五位不同。问满足以上所有条件的数有多少个。
第一行两个数n和m,分别表示大数的长度,以及限制条件的个数。接下来m行,对于第i行,有4个数li1,ri1,li2
,ri2,分别表示该限制条件对应的两个区间。
1≤n≤10^5,1≤m≤10^5,1≤li1,ri1,li2,ri2≤n;并且保证ri1-li1=ri2-li2。
一个数,表示满足所有条件且长度为n的大数的个数,答案可能很大,因此输出答案模10^9+7的结果即可。
观察发现,限制条件的本质是使得一些位置只能填同样的字符,我们不妨把限制在一起的位置看做点,在它们之间连一条边
那么统一联通块里面的位置就只能填同一字符了,所以设联通快数为 x ,那么答案就是 9×10x?1 (第一位不能填 0 ,所以少一种选择)
于是就有一个暴力的做法,用并查集维护联通块,每次对于一组限制 l1,r1,l2,r2 ,暴力将两个区间的对应点合并,复杂度 O(n2logn)
考虑怎么优化并查集的合并,由于是区间问题,所以很容易就想到用线段树或者 st 表来维护
每次把可以询问区间拆成 log 个区间,区间与区间之间进行连边,难点在于最后怎么将区间之间的合并转化到点上
由于题目只需要最终询问一次,不妨利用 lazytag 的思想,对每一种长度的区间用一个并查集来维护,最后算答案的时候将合并信息下传
具体来讲,考虑 st 表的做法:设 fa(i,j) 表示左端点为 i 的长度为 2j 的区间所在集合的 root 的左端点
那么下传信息的时候只需要 (i,j?1),(i+2j?1,j?1) 分别和 (fa(i,j),j?1) 合并即可,最后统计一下 (i,0) 的联通块数 ,总复杂度 O(nlog2n)