• [HNOI2016]最小公倍数


    题目

    不难发现题意就是,每条边有两种权值,每次询问两个点(u,v),问(u)(v)是否存在一条路径满足第一类边权的最大值为(a),第二类边权的最大值为(b)

    一个直观的暴力做法就是把(a_ileq a,b_ileq b)的边都加进来,看看加入这些边后(u,v)是否联通;如果联通,在看看(u,v)所在联通块的两种边权的最大值是否分别为(a、b);如果是,答案为Yes,否则为No。显然这个暴力可以使用并查集来实现。

    有了暴力现在开始分块,我们先将所有边按照第一类权值排序,询问按照第二类权值排序;之后分块,对于每个块我们维护一个前缀并查集,我们在处理一组询问之前会将所有第二类权值不超过这个询问的边加入这些前缀并查集中,这样我们的询问就只是查一个前缀,我们暴力把散块里的边加入到上一个并查集里就好了,询问完了再一条一条撤销回来

    时间复杂度是(O((m+q)sqrt{m}log n)),不太会将(log)放进根号里面;经过手玩,块大小在(5sqrt{m})的时候跑得最快

    代码

    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #include<bits/stdc++.h>
    #define re register
    const int maxn=5e4+5;
    const int M=1605;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||c>'9')c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct edge{unsigned short u,v;int x,y;}a[maxn<<1];
    struct Ask{unsigned short s,t,rk;int x,y;}q[maxn];
    int m,B,p[maxn<<1],id[maxn<<1],vx[maxn<<1],vy[maxn<<1],cnt,num,l[M],r[M];
    unsigned short n,Q,Ans[maxn];
    inline int max(int a,int b) {return a>b?a:b;}
    struct Dsu {
    	int C[M],D[M],top,va[maxn],vb[maxn];
    	unsigned short tp,st[M];
    	unsigned short A[M],sz[maxn],B[M],fa[maxn],f[M];
    	std::bitset<M> vis;
    	inline int find(int x) {
    		for(;x!=fa[x];x=fa[x]);return x;
    	}
    	inline int Find(int x) {
    		return x==fa[x]?x:fa[x]=Find(fa[x]);
    	}
    	inline void Merge(const int &x,const int &y,const int &a,const int &b) {
    		int xx=Find(x),yy=Find(y);
    		if(xx==yy) {
    			va[xx]=max(va[xx],a);vb[xx]=max(vb[xx],b);
    			return;
    		}
    		if(sz[xx]<sz[yy])std::swap(xx,yy);
    		if(sz[xx]==sz[yy]) sz[xx]++;fa[yy]=xx;
    		va[xx]=max(va[xx],max(va[yy],a));
    		vb[xx]=max(vb[xx],max(vb[yy],b));
    	}
    	inline void merge(const int &x,const int &y,const int &a,const int &b) {
    		int xx=find(x),yy=find(y);
    		if(xx==yy) {
    			vis[++top]=0;A[top]=xx;
    			C[top]=va[xx],D[top]=vb[xx];
    			va[xx]=max(va[xx],a),vb[xx]=max(vb[xx],b);
    			return;
    		}
    		if(sz[xx]<sz[yy]) std::swap(xx,yy);
    		vis[++top]=1;
    		A[top]=xx,B[top]=yy;fa[yy]=xx;
    		if(sz[xx]==sz[yy]) sz[xx]++,f[top]=1;else f[top]=0;
    		C[top]=va[xx],D[top]=vb[xx];
    		va[xx]=max(va[xx],max(va[yy],a));
    		vb[xx]=max(vb[xx],max(vb[yy],b));
    	}
    	inline void back() {
    		if(vis[top]) fa[B[top]]=B[top];
    		sz[A[top]]-=f[top];
    		va[A[top]]=C[top],vb[A[top]]=D[top];
    		--top;
    	}
    	inline int query(const int &x,const int &y,const int &a,const int &b) {
    		int xx=find(x),yy=find(y);
    		if(xx!=yy) return 0;
    		return va[xx]==a&&vb[xx]==b;
    	}
    	inline void build() {for(re int i=1;i<=n;i++) fa[i]=i,sz[i]=1,va[i]=vb[i]=-1;}
    }G[67];
    inline int cmp(const edge &A,const edge &B) {return A.x<B.x;}
    inline int cop(int A,int B) {return a[A].y<a[B].y;}
    inline int cxp(const Ask &A,const Ask &B) {return A.y<B.y;}
    inline int ask(int *c,int t) {
    	int l=1,r=m,nw=0;
    	while(l<=r) {
    		int mid=l+r>>1;
    		if(c[mid]==t) nw=mid;
    		if(c[mid]<=t) l=mid+1;else r=mid-1;
    	}
    	return nw;
    }
    inline void add(int t) {
    	for(re int i=p[t];i<=num;++i) G[i].Merge(a[t].u,a[t].v,a[t].x,a[t].y);
    }
    int main() {
    	n=read(),m=read();B=5*std::sqrt(m);
    	for(re int i=1;i<=m;i++)a[i].u=read(),a[i].v=read(),a[i].x=read(),a[i].y=read();
    	std::sort(a+1,a+m+1,cmp);
    	for(re int i=1;i<=m;i++)id[i]=i;
    	std::sort(id+1,id+m+1,cop);Q=read();
    	for(re int i=1;i<=m;i++) vx[i]=a[i].x;
    	for(re int i=1;i<=m;i++) vy[i]=a[id[i]].y;
    	for(re int i=1;i<=Q;++i) {
    		q[++cnt].s=read(),q[cnt].t=read(),q[cnt].x=read(),q[cnt].y=read();
    		if(ask(vx,q[cnt].x)==0||ask(vy,q[cnt].y)==0) {
    			--cnt;continue;
    		}
    		q[cnt].rk=i;
    	}
    	int L=1,R;G[0].build();
    	while(L<=m) {
    		R=L+B-1;if(R>m) R=m;++num;
    		for(re int i=L;i<=R;i++) p[i]=num;
    		l[num]=L,r[num]=R;G[num].build();L=R+1;
    	}
    	std::sort(q+1,q+cnt+1,cxp);int lp=1;
    	for(re int i=1;i<=cnt;i++) {
    		while(lp<=m&&vy[lp]<=q[i].y) add(id[lp]),lp++;
    		int pos=ask(vx,q[i].x);
    		if(p[pos+1]!=p[pos]) {
    			Ans[q[i].rk]=G[p[pos]].query(q[i].s,q[i].t,q[i].x,q[i].y);
    			continue;
    		}
    		int u=p[pos]-1,sth=0;
    		for(re int j=l[u+1];j<=pos;j++)
    			if(a[j].y<=q[i].y) ++sth,G[u].merge(a[j].u,a[j].v,a[j].x,a[j].y);
    		Ans[q[i].rk]=G[u].query(q[i].s,q[i].t,q[i].x,q[i].y);
    		while(sth--) G[u].back();
    	}
    	for(re int i=1;i<=Q;i++) puts(Ans[i]?"Yes":"No");return 0;
    }
    
  • 相关阅读:
    不同指针类型的转换
    dt7.0百度熊掌当天主动推送方法
    腾讯视频信息数据爬虫开发【核心爬虫代码】
    seo与python大数据结合给文本分词并提取高频词
    Python经典算法-猴子吃桃-思路分析
    猜数游戏-人机对战-经典的randint使用
    python模拟双色球大乐透生成算法
    python打造批量关键词排名查询工具
    python开发全自动网站链接主动提交百度工具
    centos下shell脚本kill掉mysql锁表进程【笔记】
  • 原文地址:https://www.cnblogs.com/asuldb/p/12169450.html
Copyright © 2020-2023  润新知