【NOIP模拟赛三】并查集+hash day2 third 雪后村庄(好题)
来源:互联网 发布:java摇奖机转盘 编辑:程序博客网 时间:2024/04/29 18:59
题目描述
输入
输出
输出q行,每行一个字符串“yes”或“no”(不包括引号)。
样例输入
(如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
2 43 41 2 32 3 22 4 41 2 31 3 22 3 23 4 441 3 31 3 21 4 33 4 4
样例输出
noyesnono
提示
其实我真正想写的是这道题啦……
乍一看,求瓶颈边!只要判断每个村庄中a、b瓶颈边是否小于等于k就可以了,所以使用Kruskal树来做!
但是询问和村庄数都很多,这使得q次就是q*n,无法跑过1s(废话)
那么怎么办呢?注意到其实题目并不是让我们求瓶颈边,而是判断瓶颈边是否小于等于k,或者这样说:判断只使用小于等于k的边能否使a和b连通。
我们考虑离线算法,将询问当成边一起做。使用并查集维护连通性,遇到询问时只需要判断每个村庄的a、b是否在同一并查集即可。但是这样仍然是q*n,会TLE(废话,要判断n次)。
我们考虑利用启发式合并暴力合并并查集,让每个点直接指向根节点(其实就是集合标号),合并时让节点少的标号修改成节点多的,平均复杂度便是log(n*m)。用一个hash表记录每个节点在不同村庄的集合,判断时只需要判断a和b的hash值是否相等即可。最后优化一下常数、写一写读入优化神马的,可以跑进1s。
代码如下:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define mod 1000000007 #define mod2 998244353 #define N 200005 #define M 500005 int m,n,p,q,line[N]; int Set[N],sum[N];//属于哪个集合、集合中的元素个数 int hash[N];//每个元素的哈希值 int f[N],f2[N],fir[N],nex[N]; int ans[N]; void read(int &p) { p=0; char c=getchar(); while(c<'0'||c>'9')c=getchar(); while(c>='0'&&c<='9')p=p*10+c-'0',c=getchar(); } struct node { int s,t,l,w; bool operator<(node b)const { return l==b.l?w<b.w:l>b.l; } }A[M]; void upd(int a,int k)//将a号点标号变成k O(1) { int w=(a-1)%m+1,p=(a-1)/m; hash[w]=((hash[w]+1ll*(k-Set[a])*f[p]%mod2)%mod2+mod2)%mod2; //hash2[w]=((hash2[w]+1ll*(k-Set[a])*f2[p]%mod)%mod+mod)%mod; Set[a]=k; } bool cmp(node a,node b) { if(!a.w) return 0; if(!b.w) return 1; return a.w<b.w; } int main() { read(n);read(m); for(int i=1;i<=n;i++)//200000 read(line[i]); f[0]=1; for(int i=1;i<=n;i++)//200000 f[i]=1ll*f[i-1]*7%mod2; for(int i=1;i<=n;i++)//200000 { for(int j=1;j<=line[i];j++) { read(A[p+j].s);read(A[p+j].t);read(A[p+j].l); A[p+j].s+=(i-1)*m; A[p+j].t+=(i-1)*m; } p+=line[i]; } for(int i=1;i<=n*m;i++)//200000 { upd(i,i); sum[i]=1; fir[i]=i; } read(q); for(int i=1;i<=q;i++) { read(A[p+i].s);read(A[p+i].t);read(A[p+i].l); A[p+i].w=i; } p+=q; sort(A+1,A+p+1); int x,y; for(int i=1;i<=p;i++) { x=Set[A[i].s]; y=Set[A[i].t]; if(!A[i].w) { if(x!=y) { if(sum[x]>sum[y]) swap(x,y); int j; for(j=fir[x];;j=nex[j]) { upd(j,y); if(!nex[j]) break; } nex[j]=fir[y]; fir[y]=fir[x]; sum[y]+=sum[x]; } } else ans[A[i].w]=hash[A[i].s]==hash[A[i].t]; } for(int i=1;i<=q;i++) { if(ans[i]) printf("yes\n"); else printf("no\n"); } }
阅读全文
0 0
- 【NOIP模拟赛三】并查集+hash day2 third 雪后村庄(好题)
- NOIP 2017 Day2 题1:奶酪 并查集
- [noip模拟赛]Formula 1(bfs+并查集)
- #NOIP模拟赛#字母选择Choose(并查集)
- Noip 2017 提高组 Day2 T1 奶酪(并查集)
- NOIP模拟题 2016.10.31 [DP] [搜索] [并查集]
- NOIP模拟题[递推][并查集][DP]
- [NOIP模拟题][位运算][建模][并查集]
- [NOIP模拟] Road (并查集)
- [NOIP模拟][并查集]纸带
- 2- noip模拟赛 DAY2
- 卿学姐与诡异村庄(并查集)
- 计蒜客 2017 NOIP 提高组模拟赛(三)Day2 小区划分
- 【NOIP 模拟题】刺杀大使(二分答案+并查集)
- 【NOIP 模拟题】[山东多校联合模拟赛 day1 T3] Formula 1 (BFS+并查集)
- 计蒜客 2017 NOIP 提高组模拟赛(一)Day2
- 计蒜客 2017 NOIP 提高组模拟赛(二)Day2
- 2017 NOIP 提高组模拟赛(四)Day2(计蒜客)
- 算法应用新篇
- html css 制作出翻页的时候慢慢的出来,或者放大缩小
- Linux 网络编程——TCP 粘包及其解决方案
- HashCode的理解与应用
- MATLAB2015b链接MinGW编译器
- 【NOIP模拟赛三】并查集+hash day2 third 雪后村庄(好题)
- 机器学习:朴素贝叶斯算法+中文情感分类+python
- Girls and Boys
- [leedcode]–35. Search Insert Position
- bzoj 2969: 矩形粉刷 期望
- javascript面向对象属性函数用法(defineProperty与getOwnPropertyDescriptor)
- CountDownLatch和CyclicBarrier
- 301与302
- Java的冒泡排序