zoukankan      html  css  js  c++  java
  • 【bzoj4537】 Hnoi2016—最小公倍数

    http://www.lydsy.com/JudgeOnline/problem.php?id=4537 (题目链接)

    题意

      给出一个${n}$个点${m}$条边的无向图,每条边有两个权值${a,b}$。给出$Q$个询问,问$u,v$两点间是否存在一条路径(可以不是简单路径),使得路径上的边的最大$a,b$正好等于$A,B$。

    Solution

      http://blog.csdn.net/zmh964685331/article/details/51194393

      我们考虑按照$a$的权值分块。每次找到$a$的权值在块内的询问,对它们进行处理。

      将这些询问按照$b$的大小排序以后,我们用并查集维护图的连通性。此时的边有两类,第一类就是在之前的块中的边,这些边的$a$肯定是小于询问的$a$的,我们将这些边按照$b$排序,然后依次加入。第二类就是在当前块中的边,这些边我们不好处理,直接暴for过去,如果它们的$a,b$都小于询问的$a,b$,就加入到图中,做完之后再将这些边暴力还原,因为只有$sqrt{m}$条,所以不虚。

      并查集按秩合并,同时维护连通块中$a,b$的最值。查询的时候就是判断是否$u,v$在同一连通块中,这个连通块$a,b$的最大值是否正好等于询问的$a,b$。

    细节

      块的大小,开大一点,不然会TLE。

      如果大块大块相同的$a$,我们的询问会被重复不断的加入,这是很浪费的,所以我们对这种情况进行一些处理。

      bzoj是有多慢,本机20s,交上去几乎要TLE。。。

    代码

    // bzoj4537
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf (1ll<<30)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    inline int gi() {
    	int x=0,f=1;char ch=getchar();
    	while (ch<'0' || ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    	while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int maxn=100010;
    int ans[maxn],Q,n,m,top,tot,S;
    int fa[maxn],da[maxn],db[maxn],size[maxn];
    struct option {int u,v,da,db,fa,size;}op[maxn];
    struct data {int u,v,a,b,id;}e[maxn],q[maxn],tmp[maxn];
    
    inline bool cmpa(data a,data b) {return a.a==b.a ? a.b<b.b : a.a<b.a;}
    inline bool cmpb(data a,data b) {return a.b==b.b ? a.a<b.a : a.b<b.b;}
    
    inline int find(int x) {
    	return fa[x]==x ? x : find(fa[x]);
    }
    inline void Union(int u,int v,int a,int b) {
    	u=find(u),v=find(v);
    	if (size[u]>size[v]) swap(u,v);
    	op[++tot]=(option){u,v,da[v],db[v],fa[u],size[v]};
    	if (u==v) da[v]=max(da[v],a),db[v]=max(db[v],b);
    	else {
    		fa[u]=v;size[v]+=size[u];
    		da[v]=max(da[v],max(da[u],a));
    		db[v]=max(db[v],max(db[u],b));
    	}
    }
    int main() {
    	n=gi(),m=gi();
    	for (int i=1;i<=m;i++) e[i].u=gi(),e[i].v=gi(),e[i].a=gi(),e[i].b=gi(),e[i].id=i;
    	S=(int)sqrt(3*m);
    	Q=gi();
    	for (int i=1;i<=Q;i++) q[i].u=gi(),q[i].v=gi(),q[i].a=gi(),q[i].b=gi(),q[i].id=i;
    	sort(e+1,e+1+m,cmpa);
    	sort(q+1,q+1+Q,cmpb);
    	for (int i=1;i<=m;i+=S) {
    		int L=i,R=min(i+S-1,m);
    		top=0;
    		for (int j=1;j<=Q;j++)
    			if (q[j].a>=e[L].a && (R==m || q[j].a<e[R+1].a)) tmp[++top]=q[j];   //考虑很多边a相等的情况
    		sort(e+1,e+L,cmpb);
    		for (int j=1;j<=n;j++) fa[j]=j,size[j]=1,da[j]=db[j]=-1;
    		for (int j=1,k=1;j<=top;j++) {
    			for (;k<L && e[k].b<=tmp[j].b;k++) Union(e[k].u,e[k].v,e[k].a,e[k].b);
    			tot=0;
    			for (int l=L;l<=R;l++)
    				if (e[l].a<=tmp[j].a && e[l].b<=tmp[j].b) Union(e[l].u,e[l].v,e[l].a,e[l].b);
    			int u=find(tmp[j].u),v=find(tmp[j].v);
    			ans[tmp[j].id]= u==v && da[u]==tmp[j].a && db[u]==tmp[j].b;
    			for (;tot;tot--) {
    				fa[op[tot].u]=op[tot].fa;
    				db[op[tot].v]=op[tot].db;
    				da[op[tot].v]=op[tot].da;
    				size[op[tot].v]=op[tot].size;
    			}
    		}	 
    	}
    	for (int i=1;i<=Q;i++) printf(ans[i] ? "Yes
    " : "No
    ");
    	return 0;
    }
    
  • 相关阅读:
    ASP.NET之Cookie(坑爹的Response.Cookies.Remove)
    ASP.NET 4.0中使用FreeTextBox和FCKeditor遇到安全问题警告的解决办法
    ASP.NET用户控件操作ASPX页面(在ASPX页面捕捉用户控件的事件)
    ASP.NET页面传值之Server.Transfer
    印象中的东北特色
    Python第二周之函数及其作用域
    Python第二周之字符串,列表,元组,集合,字典
    Python第一周习题集(一)
    Python第二周习题集(一)(Craps游戏 质数 公约数 公倍数 回文质数 21根火柴游戏 验证码 后缀名 骰子随机和)
    Python第一周习题集(二)
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6405710.html
Copyright © 2011-2022 走看看