您的位置:首页 > 其它

bzoj4569: [Scoi2016]萌萌哒【稀疏表+并查集】

2018-01-11 18:49 435 查看

解题思路:

考虑暴力就是O(n2)用并查集维护那些位置要填的数字相同,若最后有cnt个集合,那ans=9∗10cnt−1(第一个集合填不能填0)。

考虑类似ST表的方法,第j层把每个区间划分成前2j位和后2j位,各看做一块。两个块属于同一个集合表示其块内每位对应相同。我们开logn个并查集,每一层记录对应第j层的相同性,就可以快速处理完每个条件了。

处理完所有条件之后,我们会得到logn个并查集,然后从上往下(j从大到小)把这个相同性推到下一层去(与其父亲的左端点及中点对应合并,有点像线段树下传标记),就可以在总时间O((n+m)logn⋅α(n))的复杂度内得到最后的并查集。最后扫一遍得到集合数即可。

这题中先用ST表思想处理条件,最后统计的方法是很妙的。

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}

const int N=100005,p=1e9+7;
int n,m,ans,fa[20]
,Log
;

int find(int d,int x)
{
return fa[d][x]==x?x:fa[d][x]=find(d,fa[d][x]);
}

void merge(int d,int x,int y)
{
x=find(d,x),y=find(d,y);
if(x!=y)fa[d][x]=y;
}

int main()
{
//freopen("lx.in","r",stdin);
n=getint(),m=getint();
for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1;
for(int j=0;j<20;j++)
for(int i=1;i<=n;i++)fa[j][i]=i;
int l1,r1,l2,r2,d,x,y;
while(m--)
{
l1=getint(),r1=getint(),l2=getint(),r2=getint();
d=Log[r1-l1+1];
merge(d,l1,l2),merge(d,r1-(1<<d)+1,r2-(1<<d)+1);
}
for(int j=19;j;j--)
for(int i=1;i+(1<<j-1)<=n;i++)
{
x=i,y=find(j,x);
merge(j-1,x,y);
merge(j-1,x+(1<<j-1),y+(1<<j-1));
}
m=0;
for(int i=1;i<=n;i++)
if(fa[0][i]==i)m++;
ans=9;
for(int i=1;i<m;i++)ans=(ll)ans*10%p;
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: