P3247-[HNOI2016]最小公倍數【分塊,並查集】

Quant-Ask發表於2020-11-30

正題

題目連結:https://www.luogu.com.cn/problem/P3247


題目大意

n n n個點 m m m條邊,每條邊有 ( x , y , a , b ) (x,y,a,b) (x,y,a,b) q q q次詢問 ( x ′ , y ′ , a ′ , b ′ ) (x',y',a',b') (x,y,a,b)表示詢問是否存在一條 x ′ − > y ′ x'->y' x>y的路徑使得路徑上 a m a x = a ′ , b m a x = b ′ a_{max}=a',b_{max}=b' amax=a,bmax=b


解題思路

考慮暴力的做法,我們用加入所有 a ≤ a ′ a\leq a' aa b ≤ b ′ b\leq b' bb的邊加入,然後看 x ′ y ′ x'y' xy是否在同一連通塊且聯通塊中 a , b a,b a,b最大值是否是 a ′ , b ′ a',b' a,b

如何優化,我們把所有的邊根據 a i a_i ai的權值分成若干個塊,對於每個塊我們把所有 a ′ a' a在這個範圍的內的詢問進行處理,我們把所有處理的詢問和在塊前面的邊按照 b b b排序,然後這一部分我們就用指標掃描加入,對於在塊裡的邊我們就暴力掃描加入。

但是每個詢問做完之後注意塊裡的邊要刪去,所以我們不能用路徑壓縮,用按秩合併即可。

時間複雜度 O ( q m log ⁡ n ) O(q\sqrt m\log n) O(qm logn)


c o d e code code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
using namespace std;
const int N=1e5+10;
struct node{
	int x,y,a,b,s;
}e[N],q[N],cl[N];
int n,m,Q,tot,p[N];
int fa[N],siz[N],A[N],B[N];
bool ans[N];
bool cmpa(node x,node y)
{return x.a==y.a?(x.b<y.b):(x.a<y.a);}
bool cmpb(node x,node y)
{return x.b==y.b?(x.a<y.a):(x.b<y.b);}
int find(int x)
{return fa[x]==x?x:find(fa[x]);}
int read() {
	int x=0,f=1; char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
	while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
	return x*f;
}
void unionn(int x,int y,int a,int b){
	x=find(x),y=find(y);
	if(siz[x]>siz[y])swap(x,y);
	cl[++tot]=(node){x,y,A[y],B[y],siz[y]};
	A[y]=max(max(A[x],A[y]),a);
	B[y]=max(max(B[x],B[y]),b);
	if(x!=y)fa[x]=y;siz[y]=max(siz[y],siz[x]+1);
	return;
}
void Clear(){
	for(int i=tot;i>=1;i--){
		fa[cl[i].x]=cl[i].x;
		A[cl[i].y]=cl[i].a;
		B[cl[i].y]=cl[i].b;
		siz[cl[i].y]=cl[i].s;
	}
	tot=0;return;
}
int main()
{
//	freopen("multiple5.in","r",stdin); 
//	freopen("data.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=m;i++)
		e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read();
	Q=read();
	for(int i=1;i<=Q;i++)
		q[i].x=read(),q[i].y=read(),q[i].a=read(),q[i].b=read(),q[i].s=i;
	sort(e+1,e+1+m,cmpa);sort(q+1,q+1+Q,cmpb); 
	int T=sqrt(m*log2(n));e[m+1].a=1e9+1;
	for(int k=1;k<=m;k+=T){
		int l=k,r=min(k+T,m);int cnt=0;
		for(int i=1;i<=n;i++)fa[i]=i,A[i]=B[i]=-1,siz[i]=0;
		for(int i=1;i<=Q;i++)
			if(q[i].a>=e[l].a&&q[i].a<e[r+1].a)
				p[++cnt]=i;
		if(!cnt)continue;
		if(k)sort(e+1,e+l,cmpb);
		int pt=1;
		for(int i=1;i<=cnt;i++){
			int x=p[i];
			while(pt<l&&e[pt].b<=q[x].b)
				unionn(e[pt].x,e[pt].y,e[pt].a,e[pt].b),pt++;
			tot=0;
			for(int j=l;j<=r;j++)
				if(e[j].a<=q[x].a&&e[j].b<=q[x].b)
					unionn(e[j].x,e[j].y,e[j].a,e[j].b);
			int fx=find(q[x].x),fy=find(q[x].y);
			ans[q[x].s]=((fx==fy)&&(A[fx]==q[x].a)&&(B[fx]==q[x].b));
			Clear();
		}
	}
	for(int i=1;i<=Q;i++)
		if(ans[i])printf("Yes\n");
		else printf("No\n");
	return 0; 
}

相關文章