正解:倍增+并查集
解题报告:
最近考试考到了一道类似的题然后就想起这道回来看下,发现题解写得奇奇怪怪的我我我重构下$QwQ$
首先不难想到暴力?就考虑把区间相等转化成对应点对相等,然后直接对应点连边,最后求有几个连通块就好辣
然后看下复杂度,修改是$O(n^2)$查询是$O(n)$,就比较容易想到能不能通过一些技巧变成都是$O(nlogn)$的,结合数据范围发现$nlogn$的复杂度似乎是对的,于是就往这个方面想呗.就不难想到倍增和线段树.
考虑倍增,设$f_{i,j}$表示$[i,i+2^j-1]$这一段区间的信息.然后每次赋值操作就可以二进制拆分成$log$个区间,然后直接赋值$f_{l_1,j}=f_{l_2,j}$.
最后回答询问的时候把所有相等关系下放下去,就$f_{i,j}=f_{i,j+1},f_{i,i+2^{j-1}}=f_{i,j+1}$.
最后统计下联通块个数$cnt$,答案就$10^{cnt}$.
其实是有点类似线段树的$lazy\_tag$操作的$QwQ$
#include<bits/stdc++.h> using namespace std; #define il inline #define ll long long #define rg register #define gc getchar() #define rp(i,x,y) for(rg int i=x;i<=y;++i) #define my(i,x,y) for(rg int i=x;i>=y;--i) const int N=1e5+10,mod=1e9+7; int n,m,f[N][20],poww[20],cnt; ll as=9; il int read() { rg char ch=gc;rg int x=0;rg bool y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il void pre(){poww[0]=1;rp(i,1,19)poww[i]=poww[i-1]<<1;rp(i,1,n)rp(j,0,20)f[i][j]=i;} int fd(int x,int lth){return f[x][lth]==x?x:f[x][lth]=fd(f[x][lth],lth);} il void merg(int x,int y,int lth){int fax=fd(x,lth),fay=fd(y,lth);if(fax!=fay)f[fax][lth]=fay;} int main() { // freopen("mmd.in","r",stdin);freopen("mmd.out","w",stdout); n=read();m=read();pre(); while(m--){int l1=read(),r1=read(),l2=read(),r2=read();my(i,19,0)if(l1+poww[i]-1<=r1)merg(l1,l2,i),l1+=poww[i],l2+=poww[i];} my(j,19,1)rp(i,1,n-poww[j]+1)merg(i,fd(i,j),j-1),merg(i+poww[j-1],fd(i,j)+poww[j-1],j-1); rp(i,1,n)if(fd(i,0)==i)++cnt;rp(i,1,cnt-1)as=as*10,as%=mod; printf("%lld\n",as); return 0; }