洛谷P3295 萌萌哒 并查集 + ST表
又切一道紫题!!!
成功的(看了一吨题解之后),我A掉了第二道紫题。
好,我们仔细观察,发现这是一个排列组合问题。
有些限定条件,要相等的地方,我们就用并查集并起来。最后一查有多少个并查集,就有多少个位置可供自由选择。
所以答案就是10^(并查集数),去除前导0:*(9/10)
好,这样我们得到了一个O(mn)算法。
然后我们考虑优化:每个区间可能被合并多次。所以我们有两种选择:线段树/ST表。
考虑到这是ST表例题(???????),我们就来个ST表与并查集联动求解...
我们的ufs[i][j]代表在[i][2^j]这个区间内的情况。
然后每次合并的时候都往下合并两个j-1(也可以最后再一起下传标记)
实质上是开了logn个并查集,因为我发现find和merge都不跨层。
题外话:与RE战斗的艰辛历程
交了11次RE,实在是让人感受绝望啊。
两种方法全都RE,所幸刚才我写的时候都查出来错了。
那么先来看看第一种方法:
每次都跟线段树一样恰好标记完最少的节点,最后所有标记一起下传。
#include <cstdio>
using namespace std;
const int N = ;
const int mo = ; int ufs[N][],n,m;
int find(int x,int j)
{
if(ufs[x][j]!=x) ufs[x][j]=find(ufs[x][j],j);
return ufs[x][j];
}
void merge(int x,int y,int j)
{
ufs[find(x,j)][j]=find(y,j);///->!!这里调了一个错,之前是ufs[x][j]=......
return;
} int main()
{
scanf("%d%d",&n,&m);
for(int j=;j<=;j++)
{
for(int i=;i<=n;i++) ufs[i][j]=i;///->!
}
int a,b,c,d;
int md=;
while((<<md)<=n) md++;
md--;
for(int i=;i<=m;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
for(int j=md;j>=;j--)
{
if(a+(<<j)-<=b) merge(a,c,j),a+=(<<j),c+=(<<j);
}
}
///
for(int j=md;j>=;j--)///这里,RE的罪魁祸首!我之前写的0,结果传进去个j=-1直接挂
{
for(int i=;i+(<<j)-<=n;i++)
{
merge(i,find(i,j),j-);
merge(i+(<<(j-)),find(i,j)+(<<(j-)),j-);
}
}
///
long long ans=;
bool q=false;
for(int i=;i<=n;i++)
{
if(find(i,)==i)
{
if(q) ans=(ans*)%mo;
q=;
}
}
//for(int i=1;i<=n;i++) printf("%d ",find(i,0));
printf("%lld",ans);
return ;
}
AC代码,跑的比下面快一些
第二种思路:
每次都传到底。如果已经在一起就不往下推了。
#include <cstdio>
using namespace std;
const int N = ;
const int mo = ; int ufs[N][],n,m;
int ffind(int x,int j)
{
//if(ufs[x][j]!=x) ufs[x][j]=find(ufs[x][j],j);
//return ufs[x][j];
if(j<) return ;
int ans=x,k;
while(ufs[ans][j]!=ans) ans=ufs[ans][j];
while(ufs[x][j]!=x)
{
k=ufs[x][j];
ufs[x][j]=ans;
x=k;
}
return ans;
}
void mmerge(int x,int y,int j)
{
if(j<) return;///这里控制情况,AC
if(ffind(x,j)==ffind(y,j)) return;
ufs[ffind(x,j)][j]=ffind(y,j);///->!!
mmerge(x,y,j-),mmerge(x+(<<(j-)),y+(<<(j-)),j-);///这里RE!会传入j=-1
return;
} int main()
{
scanf("%d%d",&n,&m);
for(int j=;j<=;j++)
{
for(int i=;i<=n;i++) ufs[i][j]=i;///->!
}
int a,b,c,d;
int md=;
while((<<md)<=n) md++;
md--;
for(int i=;i<=m;i++)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
for(int j=md;j>=;j--)
{
if(a+(<<j)-<=b) mmerge(a,c,j),a+=(<<j),c+=(<<j);
}
}
/** */
long long ans=;
bool q=false;
for(int i=;i<=n;i++)
{
if(ffind(i,)==i)
{
if(q) ans=(ans*)%mo;
q=;
}
}
//for(int i=1;i<=n;i++) printf("%d ",find(i,0));
printf("%lld",ans);
return ;
}
AC代码
结论:函数里最好写上特判违法情况,保险。
洛谷P3295 萌萌哒 并查集 + ST表的更多相关文章
- bzoj 4569 [Scoi2016]萌萌哒 并查集 + ST表
题目链接 Description 一个长度为\(n\)的大数,用\(S_1S_2S_3...S_n\)表示,其中\(S_i\)表示数的第\(i\)位,\(S_1\)是数的最高位,告诉你一些限制条件,每 ...
- luogu3295 萌萌哒 (并查集+ST表)
如果给相同的位置连边,最后联通块数是n,最后答案就是$9*10^{n-1}$ 但直接连边是$O(n^2)$的 所以事先处理出一个ST表,每次O(1)地给那个ST表连边 最后再一点一点下放,就是把在这层 ...
- 【洛谷3865】 【模板】ST表(猫树)
传送门 洛谷 Solution 实测跑的比ST表快!!! 这个东西也是\(O(1)\)的,不会可以看我上一篇Blog 代码实现 代码戳这里
- 洛谷P3295 萌萌哒 [SCOI2016] 倍增+并查集
正解:倍增+并查集 解题报告: 传送门! 首先不难想到暴力?就考虑把区间相等转化成对应点对相等,然后直接对应点连边,最后求有几个连通块就好辣 然后看下复杂度,修改是O(n2)查询是O(n),就比较容易 ...
- 洛谷P4092树——并查集
题目:https://www.luogu.org/problemnew/show/P4092 利用并查集,倒序离线,那么从倒序来看被撤销标记的点就再也不会被标记,所以用并查集跳过: 莫名其妙的WA,调 ...
- 洛谷P2391 白雪皑皑(并查集)
题目背景 “柴门闻犬吠,风雪夜归人”,冬天,不期而至.千里冰封,万里雪飘.空中刮起了鸭毛大雪.雪花纷纷,降落人间. 美能量星球(pty 在 spore 上的一个殖民地)上的人们被这美景所震撼.但是 p ...
- 洛谷P3958 奶酪 并查集
两个空洞可互达当且仅当两个空洞相切,即球心距离小于等于球的直径. 一一枚举两个可互达的空洞,并用并查集连起来即可. Code: #include<cstdio> #include<c ...
- 洛谷 P3958 奶酪 并查集
目录 题面 题目链接 题面 题目描述 输入输出格式 输入格式 输出格式: 输入输出样例 输入样例 输出样例 说明 思路 AC代码 总结 题面 题目链接 P3958 奶酪 题面 题目描述 现有一块大奶酪 ...
- 洛谷 P2391.白雪皑皑 (并查集,思维)
题意:有\(n\)个点,对这些点进行\(m\)次染色,第\(i\)次染色会把区间\((i*p+q)\ mod\ N+1\)和\((i*q+p)\ mod\ N+1\)之间的点染成颜色\(i\),问最后 ...
随机推荐
- OpenGL学习(1)——创建窗口
这是我的第一篇博客,试着记录学习OpenGL的过程.使用的教程:LearnOpenGL,系统:Deepin 15.9.3,IDE:Qt Creator. 添加头文件 创建窗口用到两个库:GLFW和GL ...
- linux下向一个文件中的某行插入数据的做法
sed -i 'ni\x' test.file 表示向test.file文件里的第n行的前面添加x内容sed -i 'na\x' test.file 表示向test.file ...
- 如何用chrome查看post get及返回的数据
chrome浏览器按下F12打开开发者工具 点击Network,找到过滤器 筛选XHR,Method那一列会显示POST GET:
- PHP magic_quotes_gpc 和 addslashes解析
默认情况下,PHP 指令 magic_quotes_gpc 为 on,它主要是对所有的 GET.POST 和 COOKIE 数据自动运行 addslashes().不要对已经被 magic_quote ...
- 个人博客作业_week3
一. 评测 1.对方背景 这个好像大家都不一样,他要考四级啊,考六级啊,出国啊,或者平时写代码看不懂错误信息(呵呵)(还有可能是为了完成某次作业而用的....), 等等,所以是会用的.一般的问题都能解 ...
- 20135323符运锦期中总结----Linux系统的理解及学习心得
一.网易云课堂 1.各章节总结 第一周:计算机是如何工作的http://www.cnblogs.com/20135323fuyunjin/p/5222787.html 第二周:操作系统是如何工作的ht ...
- Linux内核分析第一次学习报告
Linux内核分析第一次学习报告 学生 黎静 学习内容 1.存储程序计算机工作模型 冯诺依曼体系结构:核心思想为存储程序计算机. CPU抽象为for循环,总是执行下一条指令,内存保存指令和数据,CPU ...
- jeecg的下拉列表
jeecg里面下拉列表的使用 ①建立数据字典seo_id <t:dictSelect field="operationPromotionAccount" typeGroupC ...
- jisuanqi
1.jisuanqi 2.https://github.com/12wangmin/text/tree/master 3.计算截图 7+8 清除 4.总结 通过课程设计,主要要达到两个目的,一是检验和 ...
- [转]java实现,输入数据,空格继续,回车结束输入
普通版:可输入,可输出.带详细的注释 import java.util.Scanner; public class SumDemo { public static void main(String[] ...