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;
    }
    
  • 相关阅读:
    LeetCode Binary Tree Inorder Traversal
    LeetCode Populating Next Right Pointers in Each Node
    LeetCode Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode Reverse Linked List II
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Pascal's Triangle
    Palindrome Construct Binary Tree from Preorder and Inorder Traversal
    Pascal's Triangle II
    LeetCode Word Ladder
    LeetCode Binary Tree Zigzag Level Order Traversal
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6405710.html
Copyright © 2011-2022 走看看