bzoj4569 [Scoi2016]萌萌哒

Description

一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2...Sr2完全相同。比如n=6时,某限制条件l1=1,r1=3,l2=4,r2=6,那么123123,351351均满足条件,但是12012,131141不满足条件,前者数的长度不为6,后者第二位与第五位不同。问满足以上所有条件的数有多少个。

Input

第一行两个数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。

Output

 一个数,表示满足所有条件且长度为n的大数的个数,答案可能很大,因此输出答案模10^9+7的结果即可。

Sample Input

4 2
1 2 3 4
3 3 3 3

Sample Output

90
 
正解:$ST$表+并查集。
首先我们可以想到一个$O(n^{2})$的暴力,那就是把所有相等的数用并查集弄起来,最后统计联通块个数计算答案就行了。
然后考虑如何优化。本能反应是想到线段树,但是线段树是没有办法维护的。
那么我们可以考虑$ST$表,虽然我也不知道怎么想到这一步。。
如果两个区间要求相等,那么我们就把每个区间分成两个区间,然后分别用并查集连起来。
最后我们直接把并查集的父亲标记下放,在最底层统计连通块个数就行了。
 
 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <set>
13 #define rhl (1000000007)
14 #define inf (1<<30)
15 #define N (100010)
16 #define il inline
17 #define RG register
18 #define ll long long
19 #define pos(i,j) (((i)-1)*20+(j)+1)
20 
21 using namespace std;
22 
23 int fa[22*N],vis[22*N],leg[N],n,m,tot;
24 
25 il int gi(){
26     RG int x=0,q=1; RG char ch=getchar();
27     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
28     if (ch=='-') q=-1,ch=getchar();
29     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
30     return q*x;
31 }
32 
33 il ll qpow(RG ll a,RG ll b){
34     RG ll ans=1;
35     while (b){
36     if (b&1) ans=ans*a%rhl;
37     a=a*a%rhl,b>>=1;
38     }
39     return ans;
40 }
41 
42 il int find(RG int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); }
43 
44 il void unionn(RG int u,RG int v,RG int leg){
45     RG int x=find(pos(u,leg)),y=find(pos(v,leg));
46     if (x!=y) fa[x]=y; return;
47 }
48 
49 int main(){
50 #ifndef ONLINE_JUDGE
51     freopen("mmd.in","r",stdin);
52     freopen("mmd.out","w",stdout);
53 #endif
54     n=gi(),m=gi(); for (RG int i=2;i<=n;++i) leg[i]=leg[i>>1]+1;
55     for (RG int j=0;j<=19;++j) for (RG int i=1;i<=n;++i) fa[pos(i,j)]=pos(i,j);
56     for (RG int i=1,l1,r1,l2,r2,len;i<=m;++i){
57     l1=gi(),r1=gi(),l2=gi(),r2=gi(),len=r1-l1+1,unionn(l1,l2,leg[len]);
58     unionn(r1-(1<<leg[len])+1,r2-(1<<leg[len])+1,leg[len]);
59     }
60     for (RG int j=19;j;--j)
61     for (RG int i=1,x;i<=n;++i)
62         if (i+(1<<j)-1<=n && find(pos(i,j))!=pos(i,j)){
63         x=(find(pos(i,j))-1)/20+1,fa[find(pos(i,j-1))]=find(pos(x,j-1));
64         fa[find(pos(i+(1<<(j-1)),j-1))]=find(pos(x+(1<<(j-1)),j-1));
65         }
66     for (RG int i=1;i<=n;++i) if (!vis[find(pos(i,0))]) vis[find(pos(i,0))]=1,++tot;
67     printf("%lld
",9*qpow(10,tot-1)%rhl); return 0;
68 }
原文地址:https://www.cnblogs.com/wfj2048/p/7260160.html