BZOJ4569 : [Scoi2016]萌萌哒
建立ST表,每层维护一个并查集。
每个信息可以拆成两条长度为$2$的幂次的区间相等的信息,等价于ST表里两对点的合并。
然后递归合并,一旦发现已经合并过了就退出。
因为一共只会发生$O(n\log n)$次合并,所以时间复杂度为$O(n\log n\alpha(n))$。
#include<cstdio> int n,m,i,j,a,b,c,d,f[17][100010],v[100010],ans=9; int F(int i,int j){return f[i][j]==j?j:f[i][j]=F(i,f[i][j]);} void merge(int p,int x,int y){ if(F(p,x)==F(p,y))return; f[p][f[p][x]]=f[p][y]; if(!p)return; p--; merge(p,x,y),merge(p,x+(1<<p),y+(1<<p)); } inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int main(){ read(n),read(m); if(n==1)return puts("10"),0; for(i=0;(1<<i)<=n;i++)for(j=1;j+(1<<i)-1<=n;j++)f[i][j]=j; while(m--){ read(a),read(b),read(c),read(d);i=31-__builtin_clz(b-a+1); merge(i,a,c),merge(i,b-(1<<i)+1,d-(1<<i)+1); } for(v[F(0,1)]=1,i=2;i<=n;i++)if(!v[F(0,i)])v[f[0][i]]=1,ans=10LL*ans%1000000007; return printf("%d",ans),0; }