[分块]bzoj4537 - cool's Blog

[分块]bzoj4537

cool posted @ 2016年7月07日 09:23 in 数据结构 , 579 阅读

4537: [Hnoi2016]最小公倍数

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 592  Solved: 251
[Submit][Status][Discuss]

Description

  给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值。所有权值都可以分解成2^a*3^b
的形式。现在有q个询问,每次询问给定四个参数u、v、a和b,请你求出是否存在一条顶点u到v之间的路径,使得
路径依次经过的边上的权值的最小公倍数为2^a*3^b。注意:路径可以不是简单路径。下面是一些可能有用的定义
:最小公倍数:K个数a1,a2,…,ak的最小公倍数是能被每个ai整除的最小正整数。路径:路径P:P1,P2,…,Pk是顶
点序列,满足对于任意1<=i<k,节点Pi和Pi+1之间都有边相连。简单路径:如果路径P:P1,P2,…,Pk中,对于任意1
<=s≠t<=k都有Ps≠Pt,那么称路径为简单路径。

Input

  输入文件的第一行包含两个整数N和M,分别代表图的顶点数和边数。接下来M行,每行包含四个整数u、v、a、
b代表一条顶点u和v之间、权值为2^a*3^b的边。接下来一行包含一个整数q,代表询问数。接下来q行,每行包含四
个整数u、v、a和b,代表一次询问。询问内容请参见问题描述。1<=n,q<=50000、1<=m<=100000、0<=a,b<=10^9

Output

  对于每次询问,如果存在满足条件的路径,则输出一行Yes,否则输出一行 No(注意:第一个字母大写,其余
字母小写) 。

Sample Input

4 5
1 2 1 3
1 3 1 2
1 4 2 1
2 4 3 2
3 4 2 2
5
1 4 3 3
4 2 2 3
1 3 2 2
2 3 2 2
1 3 4 4

Sample Output

Yes
Yes
Yes
No
No

HINT

考虑这道题的暴力算法,对于一个询问,将<=a,<=b的边都加进来,然后并查集check一下,总复杂度是O(mq*α)

可以想到类似于莫队的算法,先对边按a排序后分块,然后在计算某一块时,找出询问中符合本块a的询问。

对于前面的块的边的a,一定符合询问,所以把b排序后归并加入边,对于本块内的边暴力加,暴力删就行了(所以不能路径压缩)。

#include <cstdio>
#include <algorithm>
#include <cmath> 
#define maxn 100010
using namespace std;
void read(int &i)
{
	char x;
	for (x = getchar();x < '0';x = getchar());
	for (i = 0;x >= '0';x = getchar()) i = i * 10 + x - '0';
}
struct zhl
{
	int x,y,a,b,id;
	void init()
	{
		read(x);read(y);read(a);read(b);
	}
}e[maxn],q[maxn],tmp[maxn];
struct xfy
{
	int x,y,ma,mb,sz,f;
}re[maxn];
int cmp(zhl a,zhl b)
{
	return a.a == b.a?a.b<b.b:a.a<b.a;
}
int cmp1(zhl a,zhl b)
{
	return a.b == b.b?a.a<b.a:a.b<b.b;
}
int f[maxn],ma[maxn],mb[maxn],sz[maxn],tot,n,m,T,ans[maxn];

int find(int x)
{
	return f[x] == x?x:find(f[x]);
}
void check(int &x,int y)
{
	if (y > x) x = y;
}
void merge(int x,int y,int a,int b)
{
	int d1 = find(x),d2 = find(y);
	if (d1 == d2)
	{
		check(ma[d1],a);
		check(mb[d1],b);
		return;
	}
	if (sz[d1] > sz[d2]) swap(d1,d2);
	f[d1] = d2;sz[d2] += sz[d1];
	check(ma[d2],max(ma[d1],a));
	check(mb[d2],max(mb[d1],b));
}

void back(int x,int y)
{
	int d1 = find(x),d2 = find(y);
	if (sz[d1] > sz[d2]) swap(d1,d2);
	re[++tot].x = d1,re[tot].y = d2;
	re[tot].ma = ma[d2],re[tot].mb = mb[d2];
	re[tot].f = f[d1],re[tot].sz = sz[d2];
}

void recover()
{
	for (;tot;tot--)
	{
		int y = re[tot].y;
		f[re[tot].x] = re[tot].f;
		ma[y] = re[tot].ma;
		mb[y] = re[tot].mb;
		sz[y] = re[tot].sz;
	}
}

int main()
{
	read(n);read(m);
	for (int i = 1;i <= m;i++)
		e[i].init();
	read(T);
	for (int i = 1;i <= T;i++)
		q[i].init(),q[i].id = i;
	sort(e+1,e+m+1,cmp);
	sort(q+1,q+T+1,cmp1);
	int blk = (int)sqrt(m*log(m)/log(2));
	for (int i = 1;i <= m;i += blk)
	{
		int r1 = e[i].a,len = 0;
		for (int j = 1;j <= T;j++)
			if (q[j].a >= r1 && (i+blk > m||q[j].a < e[i+blk].a))
				tmp[++len] = q[j];
		for (int j = 1;j <= n;j++)
			f[j] = j,ma[j] = mb[j] = -1,sz[j] = 1;
		sort(e+1,e+i,cmp1);
		for (int j = 1,k = 1;j <= len;j++)
		{
			for (;k < i && tmp[j].b >= e[k].b;k++)
				merge(e[k].x,e[k].y,e[k].a,e[k].b);
			for (int w = i;w < i+blk&&w <= m;w++)
				if (e[w].a <= tmp[j].a && e[w].b <= tmp[j].b)
					back(e[w].x,e[w].y),merge(e[w].x,e[w].y,e[w].a,e[w].b);
			int d1 = find(tmp[j].x),d2 = find(tmp[j].y);
			if (d1 == d2 && ma[d1] == tmp[j].a && mb[d1] == tmp[j].b) ans[tmp[j].id] = 1;
			recover();
		}
	}
	for (int i = 1;i <= T;i++)
		ans[i]?puts("Yes"):puts("No");
	return 0;
}
AP 1st Inter Economi 说:
2022年9月08日 21:29

The AP Intermediate students can download the Economics question bank with solved study material with practice questions in chapter wise to every TM, EM, UM student, and the economics subject paper-1 AP 1st Inter Economics Model Paper and paper-2 important questions with suggestions are available through AP Jr and Sr inter Economics Model Paper 2023 Pdf with guess paper.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter
Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee