BZOJ 4569 [Scoi2016]萌萌哒 ——ST表 并查集

好题。

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);
}

  

时间: 2024-08-02 21:02:14

BZOJ 4569 [Scoi2016]萌萌哒 ——ST表 并查集的相关文章

【BZOJ-4569】萌萌哒 ST表 + 并查集

4569: [Scoi2016]萌萌哒 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 459  Solved: 209[Submit][Status][Discuss] Description 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2.

bzoj 4569: [Scoi2016]萌萌哒

4569: [Scoi2016]萌萌哒 Description 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条 件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串Sl1Sl1+1Sl1+2...Sr1与Sl2Sl2+1Sl2+2...S r2完全相同.比如n=6时,某限制条件l1=1,r1=3,l2=4,r2=6,那么123123,351351均满足条件,但是12012,13 1141不满足条件,前者数的

[SCOI2016]萌萌哒(倍增+并查集)

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

4569: [Scoi2016]萌萌哒

4569: [Scoi2016]萌萌哒 链接 分析: 每次给出的两个区间长度是一样的,对应位置的数字也是一样的,那么可以将两两对应的数字用并查集合并,设最后有$cnt$个不同的集合,答案就是$9\times 10 ^{cnt-1}$,第一个数不能是0. 暴力合并太慢了,考虑优化.对于一段区间,用倍增的思想分成log段,分别合并log段,最后的下放一下标记即可.类似线段树的懒标记. 代码: #include<cstdio> #include<algorithm> #include&l

SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页)

原文:SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页) SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程,支持单表或多表结查集分页,存储过程如下: /******************/ --Author:梦在旅途(www.Zuowenjun.cn) --CreateDate:2015-06-02 --Function:分页获取数据 /******************/ crea

BZOJ 4025 二分图(时间树+并查集)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4025 [题目大意] 给出一张图,有些边只存在一段时间,问在一个每个时间段, 这张图是否是二分图 [题解] 判断是否是二分图只要判断是否存在奇环即可, 我们对时间进行分治,在操作树上加删边, 保留涵盖时间区间的有效操作,将剩余操作按时间划分到两端的子树, 退出子树的时候撤销加边操作. 对于判断奇环,我们用并查集维护每个点与标兵的相对距离的奇偶性即可, 由于需要撤销操作,我们放弃对并查集

四川oi 萌萌哒 (分层并查集)

萌萌哒 时间限制: 1 Sec  内存限制: 256 MB提交: 12  解决: 2[提交][状态][讨论版] 题目描述 一个长度为 n 的大数,用 S1S2S3...Sn表示,其中 Si表示数的第 i 位, S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1, r1, l2, r2,即两个长度相同的区间,表示子串 Sl1Sl1+1Sl1+2...Sr1与 Sl2Sl2+1Sl2+2...Sr2完全相同.比如 n = 6 时,某限制条件 l1= 1, r1= 3, l2 = 4,

BZOJ 1015: [JSOI2008]星球大战starwar【并查集】

题目可以表述成:给定一个无向图G,每次删除它的一个点和与点相关的边集,每次询问该操作后图G的连通度(连通分量的个数).和上一题一样都是考察逆向思维,虽然删除点的做法不会,但是每次加点后询问连通度却是并查集的经典用法,所以答案可以逆过来推,具体做的时候每次加入一个点,将所有和这个点有边相连的点集合并,然后输出当前有多少个集合.细节部分需要注意的是由于点的数量十分庞大,邻接表是十分有必要的 #include<iostream> #include<cstdio> #include <

BZOJ 1854 游戏(二分图匹配或并查集)

此题的二分图匹配做法很容易想,就是把属性当做s集,武器当做t集,如果该武器拥有该武器则连一条边. 那么答案就是求该二分图的最大前i个匹配.将匈牙利算法改一改,当前找不到增广路就break. 但是过这个题需要常数优化,不能每次都fillchar一遍used数组.可以用队列将使用的used点加入,然后需要初始化的时候弹出即可. # include <cstdio> # include <cstring> # include <cstdlib> # include <i