bzoj4537【HNOI2016】最小公倍數

4537: [Hnoi2016]最小公倍數

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 563  Solved: 236
[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



分塊好題

問題轉化爲:每個邊有兩個權值a和b,每次詢問兩點之間是否存在一條路徑滿足路徑上a的最大值和b的最大值分別等於一個數。

把邊按照a排序,然後分塊。

每次處理a的範圍在當前塊內的詢問。假設處理到第i塊,把詢問和前i-1塊按照b排序,這些部分O(n)就可以處理了。第i塊裏的邊暴力處理,然後撤銷修改。然後用一個並查集維護集合最大值。




#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define N 200005
#define inf 1000000000
using namespace std;
int n,m,q,block,cnt,tot,f[N],sz[N],mxa[N],mxb[N];
bool ans[N];
struct data{int x,y,a,b,id;}a[N],b[N],c[N];
struct opt{int x,y,f,mxa,mxb,sz;}op[N];
inline int read()
{
	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;
}
inline bool cmpa(const data &a,const data &b){return a.a==b.a?a.b<b.b:a.a<b.a;}
inline bool cmpb(const data &a,const data &b){return a.b==b.b?a.a<b.a:a.b<b.b;}
int find(int x,int flg)
{
	if (f[x]==x) return x;
	if (flg) op[++tot]=(opt){x,0,f[x],0,0,0};
	return f[x]=find(f[x],flg);
}
void merge(int x,int y,int a,int b,int flg)
{
	x=find(x,flg);y=find(y,flg);
	if (sz[x]<sz[y]) swap(x,y);
	if (flg) op[++tot]=(opt){x,y,f[y],mxa[x],mxb[x],sz[x]};
	if (x==y){mxa[x]=max(mxa[x],a);mxb[x]=max(mxb[x],b);return;}
	f[y]=x;sz[x]+=sz[y];
	mxa[x]=max(mxa[x],max(mxa[y],a));
	mxb[x]=max(mxb[x],max(mxb[y],b));
}
int main()
{
	n=read();m=read();block=sqrt(m);
	F(i,1,m){a[i].x=read();a[i].y=read();a[i].a=read();a[i].b=read();a[i].id=i;}
	sort(a+1,a+m+1,cmpa);
	q=read();
	F(i,1,q){b[i].x=read();b[i].y=read();b[i].a=read();b[i].b=read();b[i].id=i;}
	sort(b+1,b+q+1,cmpb);
	for(int i=1;i<=m;i+=block)
	{
		cnt=0;
		F(j,1,q) if (b[j].a>=a[i].a&&(i+block>m||b[j].a<a[i+block].a)) c[++cnt]=b[j];
		sort(a+1,a+i,cmpb);
		F(j,1,n) f[j]=j,sz[j]=1,mxa[j]=mxb[j]=-inf;
		for(int j=1,k=1;j<=cnt;j++)
		{
			for(;k<i&&a[k].b<=c[j].b;k++) merge(a[k].x,a[k].y,a[k].a,a[k].b,0);
			tot=0;
			F(l,i,min(i+block-1,m)) if (a[l].a<=c[j].a&&a[l].b<=c[j].b) merge(a[l].x,a[l].y,a[l].a,a[l].b,1);
			int x=find(c[j].x,1),y=find(c[j].y,1);
			ans[c[j].id]=(x==y)&&(mxa[x]==c[j].a)&&(mxb[x]==c[j].b);
			D(l,tot,1)
			{
				if (!op[l].y) f[op[l].x]=op[l].f;
				else{f[op[l].y]=op[l].f;mxa[op[l].x]=op[l].mxa;mxb[op[l].x]=op[l].mxb;sz[op[l].x]=op[l].sz;}
			}
		}
	}
	F(i,1,q) puts(ans[i]?"Yes":"No");
	return 0;
}


發佈了417 篇原創文章 · 獲贊 21 · 訪問量 82萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章