题解 构树

传送门

输入中给定的边会形成一些连通块
枚举点对,若不在同一连通块中且连边后仍满足限制就连
复杂度 \(O(n^2)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int l[N], r[N];

namespace task1{
	int dsu[N], tot;
	pair<int, int> e[N];
	map<pair<int, int>, bool> mp;
	inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
	void solve() {
		for (int i=1; i<=n; ++i) dsu[i]=i;
		for (int i=1; i<=n; ++i) {
			if (mp.find({i, l[i]})==mp.end()) {
				if (find(i)==find(l[i])) {puts("-1"); return ;}
				e[++tot]={i, l[i]}, mp[{i, l[i]}]=mp[{l[i], i}]=1;
				dsu[find(i)]=find(l[i]);
			}
			if (mp.find({i, r[i]})==mp.end()) {
				if (find(i)==find(r[i])) {puts("-1"); return ;}
				e[++tot]={i, r[i]}, mp[{i, r[i]}]=mp[{r[i], i}]=1;
				dsu[find(i)]=find(r[i]);
			}
		}
		for (int i=1; i<=n; ++i)
			for (int j=l[i]; j<=r[i]; ++j)
				if (find(i)!=find(j) && i>=l[j] && i<=r[j])
					dsu[find(i)]=find(j), e[++tot]={i, j}, mp[{i, j}]=mp[{j, i}]=1;
		int rot=find(1);
		for (int i=1; i<=n; ++i) if (find(i)!=rot) {puts("-1"); return ;}
		if (tot!=n-1) {puts("-1"); return ;}
		for (int i=1; i<=tot; ++i) printf("%d %d\n", e[i].fir, e[i].sec);
	}
}

signed main()
{
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) {
		l[i]=read(), r[i]=read();
		if (max(l[i], r[i])>n || min(l[i], r[i])<1) {puts("-1"); return 0;}
	}
	task1::solve();

	return 0;
}
posted @ 2022-04-04 16:12  Administrator-09  阅读(1)  评论(0编辑  收藏  举报