洛谷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\),问最后 ...
随机推荐
- Mongodb主从复制/ 副本集/分片集群介绍
前面的文章介绍了Mongodb的安装使用,在 MongoDB 中,有两种数据冗余方式,一种 是 Master-Slave 模式(主从复制),一种是 Replica Sets 模式(副本集). Mong ...
- html5制作导航条
(1)background-repeat:no-repeat;图片不平铺 (2)使用<ul>和<li>便签,代码简介有序.易于编排. (3)在引入外部css文件时,<li ...
- JavaScript中给onclick绑定事件后return false遇到的问题
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 伪静态与重定向--RewriteRule
环境:windows 10,phpstudy,sublime text.服务器使用Apache,网站根目录为E:\phpstudy\www\,所以.htaccess放在www目录下. RewriteR ...
- Oracle 和 SQLSERVER 重新获取统计信息的方法
1. Oracle 重新获取统计信息的命令 exec dbms_stats.gather_schema_stats(ownname =>) # 需要修改 ownername options 指定 ...
- CSS 范围选择器(自编)
选择第一个到第六个li元素ul li:nth-child(n+3):not(:nth-child(n+6)){} 选择第二个到最后一个ul li:nth-child(2)~li{} 选择除了第一个和最 ...
- as_matrix、保存训练模型
#-*- coding: utf-8 -*- #构建并测试CART决策树模型 import pandas as pd #导入数据分析库 from random import shuffle #导入随机 ...
- pandas基本操作2
1.axes返回标签列表 import pandas as pd import numpy as np dates = pd.date_range(', periods=8) df = pd.Data ...
- 将ubuntu14.04 从mysql从5.5删除之后安装5.7遇到的一些问题(本篇不讨论热升级)
五一放假实在无聊 继续玩弄新的服务器.发现有台mysql版本实在有点老,估计是akiho直接使用 apt-get install mysql-server ,然后又没有更新到最新的源,然后无脑安装了5 ...
- Linux基础学习(8)--权限管理
第八章——权限管理 一.ACL权限 1.ACL权限简介与开启: (1)ACL权限简介: (2)查看分区ACL权限是否开启: (3)临时开启分区ACL权限: (4)永久开启分区ACL权限: 2.查看与设 ...