zoukankan      html  css  js  c++  java
  • [SCOI2016]萌萌哒(倍增+并查集)

    当区间([a,b])([c,d])对应相等时。
    我们把两个区间对应位置上的数所在并查集合并。
    最后并查集的数量为(num)答案就是(9*10^num)因为是个数,不能有前置(0)
    但是两个区间对应位置上的数所在并查集合并太浪费时间。
    怎么办。
    考虑使用倍增。
    我们用((i,j))代表([i,i+(1<<j)-1])这个区间然后任何一个区间最多可以(log)个这样的倍增的区间拼起来。
    然后呢?
    我们按倍增区间的大小从大往小枚举。当((x,i))((y,i))在一个并查集里时,((x,i-1))((y,i-1))在一个并查集里。((x+(1<<i-1),i-1))((y+(1<<i-1),i-1))也在一个并查集里。我们把这两对倍增区间所在并查集合并,最后长度为(1)的元素所在并查集也被合并。复杂度为(O(nlogn))
    吐槽一波题目

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define int long long
    const int mod=1e9+7;
    const int N=101000;
    int fa[N*22],id[N][22],pw[22],n,m,ans,book[N],tot,xb[N*22],l[N*22];
    int find(int x){
    	if(fa[x]==x)return x;
    	else return fa[x]=find(fa[x]);
    }
    int ksm(int x,int b){
    	int tmp=1;
    	while(b){
    		if(b&1)tmp=tmp*x%mod;
    		b>>=1;
    		x=x*x%mod;
    	}
    	return tmp;
    }
    int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return sum*f;
    }
    void pre_work(int x){
    	pw[0]=1;
    	for(int i=1;i<=20;i++)pw[i]=pw[i-1]*2;
    	int len=log2(x);
    	for(int j=0;j<=len;j++)
    		for(int i=1;i+pw[j]-1<=n;i++)
    			id[i][j]=++tot,xb[tot]=i,l[tot]=j,fa[tot]=tot;
    }
    signed main(){
    	n=read();m=read();
    	pre_work(n);
    	while(m--){
    		int a=read(),b=read();
    		int c=read(),d=read();
    		for(int i=20;i>=0;i--)
    			if(a+pw[i]-1<=b){
    				int x=find(id[a][i]),y=find(id[c][i]);
    				if(x!=y)fa[x]=y;
    				a=a+pw[i];c=c+pw[i];
    			}
    	}
    	int len=log2(n);
    	for(int j=len;j>=1;j--)
    		for(int i=1;i+pw[j]-1<=n;i++){
    			int f=find(id[i][j]);
    			int x=find(id[i][j-1]);
    			int y=find(id[xb[f]][l[f]-1]);
    			if(x!=y)fa[x]=y;
    			x=find(id[i+pw[j-1]][j-1]);
    			y=find(id[xb[f]+pw[l[f]-1]][l[f]-1]);
    			if(x!=y)fa[x]=y;
    		}
    	for(int i=1;i<=n;i++){
    		int x=find(id[i][0]);
    		if(book[x]==0)ans++,book[x]=1;
    	}
    	printf("%lld",9ll*ksm(10,ans-1)%mod);
    	return 0;
    }
    
  • 相关阅读:
    基于element-ui图片封装组件
    计算时间间隔具体每一天
    C语言学习笔记 —— 函数作为参数
    AtCoder Beginner Contest 049 题解
    AtCoder Beginner Contest 048 题解
    AtCoder Beginner Contest 047 题解
    AtCoder Beginner Contest 046 题解
    AtCoder Beginner Contest 045 题解
    AtCoder Beginner Contest 044 题解
    AtCoder Beginner Contest 043 题解
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/10520086.html
Copyright © 2011-2022 走看看