HNOI2016 最小公倍数
来源:互联网 发布:数据分析师月薪 编辑:程序博客网 时间:2024/06/06 06:38
这是HNOI2016的DAY1T1;
是一道众多CJ神犇口中的水题,也是YMD 用分块,莫队打天下的第一站;
这个题只要数学没有跪烂,应该还是可以看出来,
目标是要判定是否存在路径使x,y联通,且路上的a的最大值等于A,b的最大值等于B;
好我们先考虑暴力怎么解决;
对于前二十分,我们考虑对于每组询问,只加入a<=A且b<=B的边,在用并查集判断是否联通以及最大值是否为A和B;
好的,那么我们该怎么做呢;
首先我们身在HN,那么我们的脑海中一定要装着两个算法:莫队和CDQ,这是HN的骄傲!!
其次我们要谨记网管的教导“暴力出奇迹”,
“这题你不会,那你打个暴力就可以了嘛,暴力就可以AC嘛”;
谨记王队长的传奇“暴力进省队”;
所以这题的正解就是比纯暴力好一点点大暴力:分块!!!
思想和暴力及其类似:我们把边按照a sort,再进行分块,再把询问按照 b 进行排序;
1.我们对于每个块,先把前i-1个块中的边全部搞出来,再把对于满足这个块的a(即大于等于这个块的开头,小于等于这个块的结尾)的询问全部全部搞出来。并把搞出来的边按照b进行排序。
2.然后再枚举这些满足a的询问,有两步操作,一个是算这个块之前的贡献,一个是算这个块对当前询问的贡献;
3.第一步,因为前面已经按a排序了,所以前面的这些边的a值是一定满足询问的a的限制的,所以我们只要把已经按照b排了序的边判断是否满足询问的b的条件再依次加入
4.第二步,因为a和b都不一定满足要求,所以我们需要暴力对这个块中的边进行两次判断,即a和b都需要判断,再加入这条边;
5.并且由于满足这个块的询问的a并不一定是升序的,所以可能对于满足的两个询问i,j;
bi<bj,但ai>aj;这样就会有一个尴尬的问题,一条边的ax可能满足aj<ax<ai;显然这一条边在处理j的时候是不能算的,所以我们需要我们的并查集拥有回溯功能,即把刚刚加入的边删掉;
6.这样这个题目就可以AC了;
7.最后记得常数优化,cmp要打 const &,不然会gi烂;
// MADE BY QT666#include<cstdio>#include<algorithm>#include<cmath>#include<iostream>#include<cstdlib>#include<cstring>#include<string>#define RG registerusing namespace std;const int N=100050;int gi(){ RG int x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x;}int n,m,fa[N],maxa[N],maxb[N],size[N],tot2,tot,ans[N];int find(RG int x){return fa[x]==x?x:find(fa[x]);}struct ac{ int x,y,a,b,id;}e[N],query[N],old[N];struct AC{ int x,y,f,ma,mb,size;}add[N];bool cmpa(const ac &a,const ac &b){ if(a.a==b.a) return a.b<b.b; return a.a<b.a;}bool cmpb(const ac &a,const ac &b){ if(a.b==b.b) return a.a<b.a; return a.b<b.b;}void merge(int x,int y,int a,int b){ x=find(x),y=find(y); if(size[x]>size[y]) swap(x,y); add[++tot2]=(AC){x,y,fa[x],maxa[y],maxb[y],size[y]}; if(x==y) {maxa[y]=max(maxa[y],a),maxb[y]=max(maxb[y],b);return;} fa[x]=y;size[y]+=size[x]; maxa[y]=max(maxa[x],max(maxa[y],a)); maxb[y]=max(maxb[x],max(maxb[y],b));}void del(){ for(RG int i=tot2;i;i--) { RG int x=add[i].x,y=add[i].y; fa[x]=add[i].f,maxa[y]=add[i].ma,maxb[y]=add[i].mb,size[y]=add[i].size; } tot2=0;}int main(){ n=gi(),m=gi(); RG int block=(int)sqrt(m); for(RG int i=1;i<=m;i++) e[i].x=gi(),e[i].y=gi(),e[i].a=gi(),e[i].b=gi(),e[i].id=i; sort(e+1,e+1+m,cmpa); RG int T=gi(); for(RG int i=1;i<=T;i++) query[i].x=gi(),query[i].y=gi(),query[i].a=gi(),query[i].b=gi(),query[i].id=i; sort(query+1,query+1+T,cmpb); for(RG int i=1;i<=m;i+=block) { tot=0; for(RG int j=1;j<=T;j++){ if(query[j].a>=e[i].a&&(i+block>m||query[j].a<e[i+block].a)) { old[++tot]=query[j]; }} sort(e+1,e+1+i,cmpb); for(RG int j=1;j<=n;j++) fa[j]=j,maxa[j]=maxb[j]=-1,size[j]=1; RG int r=1; for(RG int j=1;j<=tot;j++){ for(;r<i&&e[r].b<=old[j].b;r++) { merge(e[r].x,e[r].y,e[r].a,e[r].b); } tot2=0; for(RG int l=i;l<i+block&&l<=m;l++) if(e[l].a<=old[j].a&&e[l].b<=old[j].b) {merge(e[l].x,e[l].y,e[l].a,e[l].b); } RG int x=find(old[j].x),y=find(old[j].y); if(x==y&&maxa[x]==old[j].a&&maxb[x]==old[j].b) ans[old[j].id]=1; else ans[old[j].id]=0; del(); } } for(RG int i=1;i<=T;i++) { if(ans[i]==1) puts("Yes"); else puts("No"); } return 0;}
- 【HNOI2016】最小公倍数
- HNOI2016 最小公倍数
- [HNOI2016] 最小公倍数
- BZOJ4537: [Hnoi2016]最小公倍数
- BZOJ 4537: [Hnoi2016]最小公倍数
- bzoj4537: [Hnoi2016]最小公倍数
- bzoj 4537: [Hnoi2016]最小公倍数
- bzoj4537: [Hnoi2016]最小公倍数
- 4537: [Hnoi2016]最小公倍数|分块
- bzoj4537【HNOI2016】最小公倍数
- 4537: [Hnoi2016]最小公倍数
- bzoj4537 [Hnoi2016]最小公倍数
- [BZOJ4537][Hnoi2016][分块]最小公倍数
- BZOJ 4537 [Hnoi2016]最小公倍数
- [bzoj4537][hnoi2016]最小公倍数
- BZOJ4537[HNOI2016]最小公倍数
- bzoj 4537: [Hnoi2016]最小公倍数 分块
- [分块 并查集] BZOJ 4537 [Hnoi2016]最小公倍数
- 程序猿耍题的好去处
- struts2入门
- Python中os和shutil模块实用方法集锦
- 【Git】常用命令commit提交,push推送,merge,添加分支branch
- SAP 子模块
- HNOI2016 最小公倍数
- eclipse下配置GO语言的开发环境
- Mybatis笔记一
- LeetCode 486. Predict the Winner
- OJ提交题目中的语言选项里G++与C++的区别
- 命名管道
- 1065. A+B and C (64bit) (20)
- CSU-1005
- 微信支付集成