bzoj4537: [Hnoi2016]最小公倍数
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4537
思路:把边按a排序,每sqrt(m)分一组
然后把询问按b排序,把在这组及以前的边按b排序
把这些边用并查集一条一条插入并维护
零散的部分暴力插入并记录,做完后暴力撤销
注意:并查集不能路径压缩,否则无法撤销回去
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> const int maxn=100010; using namespace std; int n,m,S,Q,top,f[maxn],maxa[maxn],maxb[maxn],ans[maxn],opcnt,siz[maxn]; struct data{ int x,y,a,b,id; void init(int i){id=i,scanf("%d%d%d%d",&x,&y,&a,&b);} void print(){printf("%d %d %d %d %d\n",x,y,a,b,id);} }e[maxn],q[maxn],stk[maxn]; struct oper{int x,y,f,maxa,maxb,siz;}op[maxn]; bool operator <(data x,data y){return x.a==y.a?x.b<y.b:x.a<y.a;} bool cmp(data x,data y){return x.b==y.b?x.a<y.a:x.b<y.b;} int find(int x){return f[x]==x?x:find(f[x]);} void merge(int x,int y,int a,int b){ x=find(x),y=find(y); if (siz[x]>siz[y]) swap(x,y); op[++opcnt]=(oper){x,y,f[x],maxa[y],maxb[y],siz[y]}; if (x==y){maxa[y]=max(maxa[y],a),maxb[y]=max(maxb[y],b);return;} f[x]=y,siz[y]+=siz[x]; maxa[y]=max(maxa[x],max(maxa[y],a)); maxb[y]=max(maxb[x],max(maxb[y],b)); } void goback(){ for (int i=opcnt;i;i--){ int x=op[i].x,y=op[i].y; f[x]=op[i].f,maxa[y]=op[i].maxa,maxb[y]=op[i].maxb,siz[y]=op[i].siz; } opcnt=0; } int main(){ scanf("%d%d",&n,&m),S=(int)sqrt(m); for (int i=1;i<=m;i++) e[i].init(i); sort(e+1,e+1+m); //for (int i=1;i<=m;i++) e[i].print(); scanf("%d",&Q); for (int i=1;i<=Q;i++) q[i].init(i); sort(q+1,q+1+Q,cmp); //for (int i=1;i<=Q;i++) q[i].print(); for (int i=1;i<=m;i+=S){ top=0; for (int j=1;j<=Q;j++) if (q[j].a>=e[i].a&&(i+S>m||q[j].a<e[i+S].a)) stk[++top]=q[j]; //printf("\ni: %d\n",i);for (int j=1;j<=top;j++) stk[j].print(); sort(e+1,e+1+i,cmp); for (int j=1;j<=n;j++) f[j]=j,maxa[j]=maxb[j]=-1,siz[j]=1; for (int j=1,k=1;j<=top;j++){ for (;k<i&&e[k].b<=stk[j].b;k++) merge(e[k].x,e[k].y,e[k].a,e[k].b); opcnt=0; for (int l=i;l<i+S&&l<=m;l++) if (e[l].a<=stk[j].a&&e[l].b<=stk[j].b) merge(e[l].x,e[l].y,e[l].a,e[l].b); int x=find(stk[j].x),y=find(stk[j].y); ans[stk[j].id]=(x==y&&maxa[x]==stk[j].a&&maxb[x]==stk[j].b); goback(); } } for (int i=1;i<=Q;i++) puts(ans[i]?"Yes":"No"); return 0; }