把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P6830 [IOI2020]连接擎天树

题面传送门
其实IOI题目一出来就口胡出这道题了,然而一直不想打,直到WC之后想缓解一下WC爆炸的心情,所以滚来写这道题。
这道题果然没有让我失望!
我们可以考虑一件事情:只要有\(p{i,j}=3\)或一个联通块中有两个环,那么一定无解。因为这样子一定有至少一个\(p_{i,j}=4\)
这样就少掉了一种情况。
之后我们可以考虑以\(p{i,j}=0\)为界,将整个图割成若干个联通块。
之后因为只有一个环,所以先缩点掉所有\(p{i,j}=1\)的情况,然后把剩下的扔到环上判是否无解即可。
注意二元环也是无解。
代码实现(注释中是调试的交互库):

#include<cstdio>
#include<vector>
using namespace std;
int n,a[1039][1039],f[1039],un,wn,fa[1039],last[1039],flag[1039],vis[1039];
//flag表示当前点是否为单点,vis表示当前所在的联通块是不是树 
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(int x,int y){
	un=find(x);wn=find(y);
	if(un==wn) return;f[un]=wn;
}
void build(std::vector<std::vector<int> > b);
int construct(std::vector<std::vector<int> > p){
	register int i,j;n=p.size();
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++) a[i][j]=p[i-1][j-1],p[i-1][j-1]=0;
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++) if(a[i][j]==3) return 0;
	}
	for(i=1;i<=n;i++) f[i]=i;
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++) if(a[i][j]==1) merge(i,j);
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++)if(find(i)==find(j)&&a[i][j]^1) return 0;
	}
	for(i=1;i<=n;i++) if(find(i)!=i) flag[i]=1,flag[find(i)]=1;
	for(i=1;i<=n;i++){
		if(flag[i]&&find(i)!=i) p[i-1][find(i)-1]=p[find(i)-1][i-1]=1;
	}
	for(i=1;i<=n;i++) fa[i]=find(i);
	for(i=1;i<=n;i++) f[i]=i;
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++) if(a[i][j]==2)merge(fa[i],fa[j]); 
	}
	for(i=1;i<=n;i++) if(find(i)!=i) vis[i]=1,vis[find(i)]=1;
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++){
			if(fa[i]!=fa[j]&&find(fa[i])==find(fa[j])&&a[i][j]^2) return 0;
		}
	}
	for(i=1;i<=n;i++) if(vis[i]&&find(i)==i) last[i]=i;
	for(i=1;i<=n;i++) if(vis[i]&&find(i)!=i) p[last[find(i)]-1][i-1]=p[i-1][last[find(i)]-1]=1,last[find(i)]=i;
	for(i=1;i<=n;i++){
		if(vis[i]&&find(i)==i){
			if(p[last[i]-1][i-1]) return 0;
			p[last[i]-1][i-1]=p[i-1][last[i]-1]=1;
		}
	}
	return build(p),1;
}
/*void build(std::vector<std::vector<int> > b){
	register int i,j;int n=b.size();
	for(i=0;i<n;i++){
		for(j=0;j<n;j++) printf("%d ",b[i][j]);printf("\n");
	}
}
int main(){
	freopen("1.in","r",stdin);
	vector<vector<int> > a;
	vector<int> b;
	a.clear();int n,x;
	register int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		b.clear();
		for(j=1;j<=n;j++) scanf("%d",&x),b.push_back(x);
		a.push_back(b);
	}
	printf("%d\n",construct(a));
}*/
posted @ 2021-02-05 20:21  275307894a  阅读(55)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end