zoukankan      html  css  js  c++  java
  • 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
    ",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("
    i: %d
    ",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;
    }



  • 相关阅读:
    常用集体名词的用法
    囊中羞涩的表达
    《当幸福来敲门》观后感
    <肖申克的救赎>观后感
    心语4
    补充:回答网友的问题,如何不用路径,而直接将CImage画到DC中,之后DC一起显示.
    线程中对变量的用法
    添加按键变量数组,就是很多同种类型按键关联变量,这些变量是一个数组;
    不容按钮、下拉框 执行同一个函数或者同一种函数的用法
    CImage显示位图与CDC双缓冲冲突,使用路径层解决.
  • 原文地址:https://www.cnblogs.com/thythy/p/5493638.html
Copyright © 2011-2022 走看看