倍增并查集
适用于一个区间向另一个区间连边,形如:
for(int i=1;i<=r1-l1+1;++i)
merge(l1+i-1,l2+i-1);
开log个并查集,用表示的区间左端点编号,合并的时候像RMQ一样拆区间,递归即可
每个$2^i$的i最多合并$n-1$次,复杂度$O(n*logn)$
萌萌哒:
统计最后的集合个数x,答案为$10^{x-1}*9$
1 #include<bits/stdc++.h>
2 #define MAXN 100005
3 #define LL long long
4 using namespace std;
5 const int mod=1e9+7;
6 inline int read(){
7 int s=0,w=0;char ch=getchar();
8 while(ch<'0'||ch>'9')w|=(ch=='-'),ch=getchar();
9 while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
10 return w?-s:s;
11 }
12 #define kd (read())
13 inline int qpow(int a,int b){
14 int res=1;
15 for(;b;b>>=1,a=(LL)a*a%mod)
16 if(b&1)res=(LL)res*a%mod;
17 return res;
18 }
19 int n,m;
20 int fat[18][MAXN],LOG[MAXN];
21 inline int find(int x,int I){
22 return fat[I][x]=fat[I][x]==x?x:find(fat[I][x],I);
23 }
24 int sum=0;
25 void fenzhi(int x,int y,int I){
26 if(find(x,I)==find(y,I))return ;
27 fat[I][find(x,I)]=find(y,I);
28 if(!I)return sum--,void();
29 fenzhi(x,y,I-1);
30 fenzhi(x+(1<<I-1),y+(1<<I-1),I-1);
31 return ;
32 }
33 int main(){
34 n=kd;m=kd;
35 for(int i=2;i<=n;++i)
36 LOG[i]=LOG[i>>1]+1;
37 for(int i=1;i<=n;++i)
38 for(int j=0;j<18;++j)
39 fat[j][i]=i;
40 sum=n;
41 int l1,l2,r1,r2,k;
42 while(m--){
43 l1=kd,r1=kd,l2=kd,r2=kd;
44 k=LOG[r1-l1+1];
45 fenzhi(l1,l2,k);
46 fenzhi(r1-(1<<k)+1,r2-(1<<k)+1,k);
47 }printf("%d\n",9LL*qpow(10,sum-1)%mod);
48 return 0;
49 }
Endless:
平方串套路对于每个长度$x$,标记$\frac{n}{x}$个关键点,每个关键点$i$,统计$i$和$i-1$的最长公共后缀+$i$和$i+1$的最长公共前缀,得到的区间所有长度为二倍$x$的串都是平方串,用$hash$二分或者$sa$,然后倍增并查集。因为考虑最小生成树,所以x按权值排序枚举,每次递归到$2^0$以为着加边。
1 #include<bits/stdc++.h>
2 #define MAXN 300005
3 #define LL long long
4 using namespace std;
5 const LL mo1=1e9+7,mo2=998244353,p=1e6;
6 inline int read(){
7 int s=0,w=0;char ch=getchar();
8 while(ch<'0'||ch>'9')w|=(ch=='-'),ch=getchar();
9 while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
10 return w?-s:s;
11 }
12 #define kd (read())
13 int n;
14 int a[MAXN];
15 int LOG[MAXN];
16 int fat[20][MAXN];
17 LL qsm1[MAXN],qsm2[MAXN],bin1[MAXN],bin2[MAXN];
18 inline LL cal1(int l,int r){
19 return (qsm1[r]-qsm1[l-1]*bin1[r-l+1]%mo1+mo1)%mo1;
20 }
21 inline LL cal2(int l,int r){
22 return (qsm2[r]-qsm2[l-1]*bin2[r-l+1]%mo2+mo2)%mo2;
23 }
24 struct node{
25 int len,val;
26 friend bool operator <(const node &a,const node &b){
27 return a.val<b.val;
28 }
29 }Q[MAXN>>1];
30 inline int find(int x,int I){
31 return fat[I][x]==x?x:fat[I][x]=find(fat[I][x],I);
32 }
33 long long ans=0;
34 void fenzhi(int x,int y,int I,int w){
35 if(find(x,I)==find(y,I))return ;
36 fat[I][find(x,I)]=find(y,I);
37 if(!I)return ans+=w,void();
38 fenzhi(x,y,I-1,w),fenzhi(x+(1<<I-1),y+(1<<I-1),I-1,w);
39 return ;
40 }
41 void merge(int l1,int r1,int l2,int r2,int w){
42 int k=LOG[r1-l1+1];
43 fenzhi(l1,l2,k,w),fenzhi(r1-(1<<k)+1,r2-(1<<k)+1,k,w);
44 return ;
45 }
46 void work(){
47 n=kd;ans=0;
48 for(int i=1;i<=n;++i){
49 a[i]=kd;
50 qsm1[i]=(qsm1[i-1]*p%mo1+a[i])%mo1;
51 qsm2[i]=(qsm2[i-1]*p%mo2+a[i])%mo2;
52 for(int j=0;j<=19;++j)fat[j][i]=i;
53 }
54 for(int i=1;i<=(n>>1);++i)
55 Q[i].val=kd,Q[i].len=i;
56 sort(Q+1,Q+(n>>1)+1);
57 for(int I=1;I<=(n>>1);++I){
58 int len=Q[I].len,w=Q[I].val;
59 //cout<<len<<" "<<w<<endl;
60 for(int i=1;i<=n;i+=len){
61 int L,R;
62 if(i!=1){
63 int rr=min(i+len-1,n);
64 int l=0,r=min(len,min(i+len-1,n)-i+1);
65 while(r-l>1){
66 int mid=l+r>>1;
67 if(cal1(rr-mid+1,rr)==cal1(i-1-mid+1,i-1)
68 &&cal2(rr-mid+1,rr)==cal2(i-1-mid+1,i-1))
69 l=mid;
70 else r=mid;
71 }
72 if(cal1(rr-r+1,rr)==cal1(i-1-r+1,i-1)
73 &&cal2(rr-r+1,rr)==cal2(i-1-r+1,i-1))
74 L=i-1-r+1;
75 else L=i-1-l+1;
76 }else L=i;
77 if(i+len<=n){
78 int l=0,r=min(len,min(i+2*len-1,n)-(i+len)+1);
79 while(r-l>1){
80 int mid=l+r>>1;
81 if(cal1(i,i+mid-1)==cal1(i+len,i+len+mid-1)
82 &&cal2(i,i+mid-1)==cal2(i+len,i+len+mid-1))
83 l=mid;
84 else r=mid;
85 }
86 if(cal1(i,i+r-1)==cal1(i+len,i+len+r-1)
87 &&cal2(i,i+r-1)==cal2(i+len,i+len+r-1))
88 R=i+len+r-1;
89 else R=i+len+l-1;
90 }else R=min(i+len-1,n);
91 //cout<<"HH "<<i<<" "<<L<<" "<<R<<endl;
92 if(R-L+1>=2*len){
93 //cout<<L<<" "<<R-len<<" "<<L+len<<" "<<R<<endl;
94 merge(L,R-len,L+len,R,w);
95 }
96 }
97 }printf("%lld\n",ans);
98 return ;
99 }
100 int main(){
101 //freopen("1.in","r",stdin);
102 freopen("endless.in","r",stdin);
103 freopen("endless.out","w",stdout);
104 bin1[0]=bin2[0]=1;
105 for(int i=1;i<=3e5;++i)bin1[i]=bin1[i-1]*p%mo1,bin2[i]=bin2[i-1]*p%mo2;
106 for(int i=2;i<=3e5;++i)LOG[i]=LOG[i>>1]+1;
107 int T=kd;
108 while(T--)work();
109 return 0;
110 }