• UOJ#465. 【HNOI2019】校园旅行 其他


    原文链接www.cnblogs.com/zhouzhendong/p/UOJ465.html

    前言

    tmd并查集写挂,调到自闭。

    cly和我写挂了同一个地方。

    一下救了两个人感觉挺开心。

    题解

    首先直接写 bfs/记忆化dfs 可以容易地得到一个 $O(m^2)$ ,或者 $O(nm)$ 的做法。常数不大的情况下应该可以得到 70 分。

    注意到本题中不要求简单路径,同一条边可以经过多次。

    这意味着,我们可以在有边相连的两个同色节点之间来回走。

    那么,假设两个点在同一个同色连通块,那么从其中一个点到另一个点的路径的有效信息本质只有两种:是否存在长度为奇数的路径、是否存在长度为偶数的路径。

    于是,对于一个同色连通块,我们只需要保留一个带奇环的基环树即可,如果没有满足条件的基环树,就保留一个树。

    然后我们考虑拆除所有连接同色点的边,留下所有连接不同色点的边。

    类似的,对于剩下的边,我们只要留下一座边数尽量多的生成森林即可。

    我丝薄了,写了个并查集维护。其实直接 dfs 就好了。

    于是剩下 $O(n)$ 条边,只要做一做最开始的暴力就好了。

    时间复杂度 $O(mcdot alpha(n) + n^2)$ 或 $O(m + n ^2)$ 。

    代码

    #pragma GCC optimize("Ofast","inline")
    #include <bits/stdc++.h>
    #define clr(x) memset(x,0,sizeof (x))
    #define For(i,a,b) for (int i=a;i<=b;i++)
    #define Fod(i,b,a) for (int i=b;i>=a;i--)
    #define pb(x) push_back(x)
    #define mp(x,y) make_pair(x,y)
    #define fi first
    #define se second
    #define real __zzd001
    #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
    #define outval(x) printf(#x" = %d
    ",x)
    #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
    #define outtag(x) puts("----------"#x"----------")
    #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);
    						For(_v2,L,R)printf("%d ",a[_v2]);puts("");
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector <int> vi;
    LL read(){
    	LL x=0,f=0;
    	char ch=getchar();
    	while (!isdigit(ch))
    		f|=ch=='-',ch=getchar();
    	while (isdigit(ch))
    		x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	return f?-x:x;
    }
    const int N=5005,M=500005;
    int n,m,q;
    vector <int> e[N];
    char s[N];
    struct Edge{
    	int x,y;
    }E[M];
    int r[N];
    namespace S1{
    	int fa[N],d[N];
    	void init(){
    		For(i,1,n)
    			fa[i]=i;
    		clr(d);
    	}
    	int getf(int x){
    		if (fa[x]==x)
    			return x;
    		int f=getf(fa[x]);
    		d[x]^=d[fa[x]];
    		return fa[x]=f;
    	}
    }
    namespace S2{
    	int fa[N];
    	void init(){
    		For(i,1,n)
    			fa[i]=i;
    	}
    	int getf(int x){
    		return fa[x]==x?x:fa[x]=getf(fa[x]);
    	}
    }
    int f[N][N];
    int qx[N*N],qy[N*N],head=0,tail=0;
    void Push(int x,int y){
    	if (x>y)
    		swap(x,y);
    	if (!f[x][y]){
    		f[x][y]=1;
    		tail++;
    		qx[tail]=x;
    		qy[tail]=y;
    	}
    }
    int main(){
    	n=read(),m=read(),q=read();
    	scanf("%s",s+1);
    	For(i,1,m)
    		E[i].x=read(),E[i].y=read();
    	S1::init(),S2::init();
    	For(i,1,m){
    		int x=E[i].x,y=E[i].y;
    		if (s[x]==s[y]){
    			if (S1::getf(x)!=S1::getf(y)){
    				e[x].pb(y),e[y].pb(x);
    				S1::d[S1::getf(x)]=S1::d[x]^S1::d[y]^1;
    				S1::fa[S1::fa[x]]=S1::getf(y);
    			}
    		}
    		else {
    			if (S2::getf(x)!=S2::getf(y)){
    				e[x].pb(y),e[y].pb(x);
    				S2::fa[S2::getf(x)]=S2::getf(y);
    			}
    		}
    	}
    	For(i,1,m){
    		int x=E[i].x,y=E[i].y;
    		S1::getf(x),S1::getf(y);
    		if (s[x]==s[y]&&!r[S1::getf(x)]&&S1::d[x]==S1::d[y]){
    			r[S1::getf(x)]=1;
    			e[x].pb(y),e[y].pb(x);
    		}
    	}
    	For(i,1,n)
    		Push(i,i);
    	For(i,1,m)
    		if (s[E[i].x]==s[E[i].y])
    			Push(E[i].x,E[i].y);
    	while (head<tail){
    		head++;
    		int x=qx[head],y=qy[head];
    		for (auto a : e[x])
    			for (auto b : e[y])
    				if (s[a]==s[b])
    					Push(a,b);
    	}
    	while (q--){
    		int x=read(),y=read();
    		if (x>y)
    			swap(x,y);
    		puts(f[x][y]?"YES":"NO");
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    windows 下读取文件夹下所有文件的文件名
    centos7安装python3
    python 实现google 在线中英文翻译
    删除docker /var/lib/docker报Device or resource busy问题处理
    java list 去重
    OpenStack与KVM的区别与联系
    虚拟化kvm virsh 常用命令
    linux 监控服务器流量
    openstack 全套学习资料地址
    二、Openstack入坑指南
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/UOJ465.html
Copyright © 2020-2023  润新知