1. 程式人生 > >BZOJ 4569 [Scoi2016]萌萌噠 ——ST表 並查集

BZOJ 4569 [Scoi2016]萌萌噠 ——ST表 並查集

oid include long long amp else n) div 每一個 並查集

好題。

ST表又叫做稀疏表,這裏利用了他的性質。

顯然每一個條件可以分成n個條件,顯然過不了。

然後發現有許多狀態是重復的,首先考慮線段樹,沒什麽卵用。

然後ST表,可以每一層表示對應的區間大小的兩個部分是否合並,如果合並就不向下遞歸。

然後可以剪去許多狀態,變成了$O(nlogn)$的。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
 
using namespace std;
#define maxn 100005
#define ll long long
#define md 1000000007
#define F(i,j,k) for (int i=j;i<=k;++i)
 
int f[maxn][21],n,m,l1,r1,l2,r2,lg[maxn];
 
int gf(int a,int t)
{
    if (f[a][t]==a) return a;
    else return f[a][t]=gf(f[a][t],t);
}
 
void merge(int a,int b,int t)
{
    int fa=gf(a,t),fb=gf(b,t);
    if (fa==fb) return ;
    f[fa][t]=fb; if (!t) return ;
    merge(a,b,t-1);merge(a+(1<<(t-1)),b+(1<<(t-1)),t-1);
}
 
int main()
{
    scanf("%d%d",&n,&m);
    F(i,2,n) lg[i]=lg[i>>1]+1;
    F(i,1,n) F(j,0,lg[n]) f[i][j]=i;
    while(m--)
    {
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        int tmp=lg[r1-l1+1];merge(l1,l2,tmp);
        merge(r1-(1<<tmp)+1,r2-(1<<tmp)+1,tmp);
    }
    int cnt=0,ans=9;
    F(i,1,n) if (f[i][0]==i) cnt++; cnt--;
    while(cnt--) {ans=(ll)ans*10%md;}
    printf("%d\n",ans);
}

  

BZOJ 4569 [Scoi2016]萌萌噠 ——ST表 並查集