题解 卷王
发现 \(|s|>3\) 时无解
发现 \(|s|\leqslant 3\) 时可以分 7 中情况大力分类讨论
核心思路是构造大度数点
懒得展开讨论了
AC code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define pb push_back
#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 p[N];
namespace force{
int head[20], fa[20], dsu[20], ecnt, maxlen;
vector<int> buc[20];
struct edge{int to, next;}e[40];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
void dfs2(int u, int fa, int dis) {
buc[dis].pb(u);
maxlen=max(maxlen, dis);
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dfs2(v, u, dis+1);
}
}
int getp(int u) {
maxlen=0;
for (int i=0; i<=n; ++i) buc[i].clear();
dfs2(u, 0, 0);
if (buc[maxlen].size()>1) return -1;
else return buc[maxlen][0];
}
void dfs1(int u) {
if (u>n) {
for (int i=1; i<=n; ++i) dsu[i]=i;
int cnt=0;
for (int i=1; i<=n; ++i) if (fa[i]) dsu[find(fa[i])]=find(i), ++cnt;
if (cnt!=n-1) return ;
int t=find(1);
for (int i=2; i<=n; ++i) if (find(i)!=t) return ;
memset(head, -1, sizeof(head)); ecnt=0;
for (int i=1; i<=n; ++i) if (fa[i]) add(fa[i], i), add(i, fa[i]);
for (int i=1; i<=n; ++i) if (getp(i)!=p[i]) return ;
puts("Possible");
for (int i=1; i<=n; ++i) if (fa[i]) printf("%d %d\n", fa[i], i);
exit(0);
}
for (int i=0; i<=n; ++i) if (i!=u) fa[u]=i, dfs1(u+1);
}
void solve() {
dfs1(1);
puts("Impossible");
exit(0);
}
}
namespace task1{
int uni[N], cnt[N], usiz;
vector<int> sets, sett, neg;
void solve() {
if (n==1) {puts(p[1]==1?"Possible":"Impossible"); exit(0);}
for (int i=1; i<=n; ++i) uni[++usiz]=p[i];
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
if (usiz>3) {puts("Impossible"); exit(0);}
for (int i=1; i<=n; ++i) if (p[i]==i) {puts("Impossible"); exit(0);}
for (int i=1; i<=n; ++i) for (int j=1; j<=usiz; ++j) if (p[i]==uni[j]) ++cnt[j];
if (usiz==1) {
assert(uni[1]==-1);
if (n<=3) {puts("Impossible"); exit(0);}
puts("Possible");
for (int i=2; i<=n; ++i) printf("1 %d\n", i);
exit(0);
}
else if (usiz==2) {
if (uni[1]==-1 || uni[2]==-1) {
int t=(uni[1]==-1)?uni[2]:uni[1];
for (int i=1; i<=n; ++i)
if (p[i]==-1) {if (i!=t) neg.pb(i);}
else sett.pb(i);
if (neg.size()+1==2 && sett.size()>2) {
puts("Possible");
int link=neg.back(); neg.pop_back();
int t1=sett.back(); sett.pop_back();
printf("%d %d\n", t, link);
printf("%d %d\n", link, t1);
for (auto it:sett) printf("%d %d\n", t1, it);
exit(0);
}
else if (sett.size()<3||neg.size()+1<3) {puts("Impossible"); exit(0);}
else {
puts("Possible");
int linkt=sett.back(); sett.pop_back();
int link1=neg.back(); neg.pop_back();
int link2=neg.back(); neg.pop_back();
printf("%d %d\n", link1, link2);
printf("%d %d\n", link2, t);
printf("%d %d\n", link1, linkt);
for (auto it:sett) printf("%d %d\n", linkt, it);
for (auto it:neg) printf("%d %d\n", link1, it);
exit(0);
}
}
else {
int s=uni[1], t=uni[2];
if (p[s]!=t || p[t]!=s) {puts("Impossible"); exit(0);}
for (int i=1; i<=n; ++i)
if (p[i]==s) {if (i!=t) sets.pb(i);}
else {if (i!=s) sett.pb(i);}
if (sets.size()+1==1 && sett.size()+1==1) force::solve();
else if (sets.size()+1==2 && sett.size()+1==2) force::solve();
else if (sets.size()+1<3 || sett.size()+1<3) {puts("Impossible"); exit(0);}
else {
puts("Possible");
int s1=sets.back(); sets.pop_back();
int s2=sets.back(); sets.pop_back();
int t1=sett.back(); sett.pop_back();
int t2=sett.back(); sett.pop_back();
printf("%d %d\n", t, s2);
printf("%d %d\n", s2, s1);
printf("%d %d\n", s1, t1);
printf("%d %d\n", t1, t2);
printf("%d %d\n", t2, s);
for (auto it:sets) printf("%d %d\n", s1, it);
for (auto it:sett) printf("%d %d\n", t1, it);
exit(0);
}
}
}
else {
if (uni[1]!=-1) {puts("Impossible"); exit(0);}
int s=uni[2], t=uni[3];
if (p[s]!=t || p[t]!=s) {puts("Impossible"); exit(0);}
for (int i=1; i<=n; ++i)
if (p[i]==s) {if (i!=t) sets.pb(i);}
else if (p[i]==t) {if (i!=s) sett.pb(i);}
else neg.pb(i);
if (sets.size()+1==2 && sett.size()+1==2) {
puts("Possible");
int s1=sets.back(); sets.pop_back();
int t1=sett.back(); sett.pop_back();
int link=neg.back(); neg.pop_back();
printf("%d %d\n", s, t1);
printf("%d %d\n", t1, link);
printf("%d %d\n", link, s1);
printf("%d %d\n", s1, t);
for (auto it:neg) printf("%d %d\n", link, it);
exit(0);
}
else if (sets.size()+1>=3 && sett.size()+1>=3) {
puts("Possible");
int s1=sets.back(); sets.pop_back();
int s2=sets.back(); sets.pop_back();
int t1=sett.back(); sett.pop_back();
int t2=sett.back(); sett.pop_back();
int link=neg.back(); neg.pop_back();
printf("%d %d\n", s, t2);
printf("%d %d\n", t2, t1);
printf("%d %d\n", t1, link);
printf("%d %d\n", link, s1);
printf("%d %d\n", s1, s2);
printf("%d %d\n", s2, t);
for (auto it:neg) printf("%d %d\n", link, it);
for (auto it:sets) printf("%d %d\n", s1, it);
for (auto it:sett) printf("%d %d\n", t1, it);
exit(0);
}
else if (sets.size()+1==1 && sett.size()+1==1 && neg.size()==1) {
puts("Possible");
printf("%d %d\n", s, neg.back());
printf("%d %d\n", t, neg.back());
exit(0);
}
else {puts("Impossible"); exit(0);}
}
}
}
signed main()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
n=read();
for (int i=1; i<=n; ++i) p[i]=read();
//force::solve();
task1::solve();
return 0;
}
rand.cpp
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define pb push_back
#define ll long long
//#define int long long
int n;
int p[N], dis[N];
vector<int> e[N];
void dfs(int u, int fa) {
for (auto v:e[u]) {
if (v==fa) continue;
dis[v]=dis[u]+1;
dfs(v, u);
}
}
signed main()
{
freopen("tree.in", "w", stdout);
random_device(seed);
mt19937 rand(seed());
#if 0
n=rand()%9+1;
cout<<n<<endl;
for (int i=2; i<=n; ++i) {
int fa=rand()%(i-1)+1;
e[fa].pb(i); e[i].pb(fa);
}
for (int i=1; i<=n; ++i) {
memset(dis, 0, sizeof(dis));
dfs(i, 0);
int maxn=0, cnt=0, lst;
for (int j=1; j<=n; ++j) maxn=max(maxn, dis[j]);
for (int j=1; j<=n; ++j) if (dis[j]==maxn) ++cnt, lst=j;
if (cnt>1) p[i]=-1;
else p[i]=lst;
}
for (int i=1; i<=n; ++i) cout<<p[i]<<' '; cout<<endl;
#endif
int n=rand()%8+1;
cout<<n<<endl;
for (int i=1; i<=n; ++i) {
if (rand()&1) cout<<-1<<' ';
else cout<<rand()%n+1<<' ';
} cout<<endl;
return 0;
}
check.cpp
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define pb push_back
#define ll long long
//#define int long long
int n;
int p[N], dis[N], dsu[N];
vector<int> e[N];
char s[N], t[N];
inline int find(int p) {return dsu[p]==p?p:dsu[p]=find(dsu[p]);}
void dfs(int u, int fa) {
for (auto v:e[u]) {
if (v==fa) continue;
dis[v]=dis[u]+1;
dfs(v, u);
}
}
//要用暴力check下是否真的无解
signed main()
{
freopen("tree.in", "r", stdin);
cin>>n;
for (int i=1; i<=n; ++i) cin>>p[i];
freopen("std.out", "r", stdin);
cin>>t;
freopen("tree.out", "r", stdin);
cin>>s;
assert(s[0]==t[0]);
if (s[0]=='I') return 0;
for (int i=1; i<=n; ++i) dsu[i]=i;
for (int i=1,u,v; i<n; ++i) {
cin>>u>>v;
e[u].pb(v); e[v].pb(u);
dsu[find(u)]=find(v);
}
int t=find(1);
for (int i=2; i<=n; ++i) assert(find(i)==t);
for (int i=1; i<=n; ++i) {
memset(dis, 0, sizeof(dis));
dfs(i, 0);
int maxn=0, cnt=0, lst;
for (int j=1; j<=n; ++j) maxn=max(maxn, dis[j]);
for (int j=1; j<=n; ++j) if (dis[j]==maxn) ++cnt, lst=j;
int t;
if (cnt>1) t=-1;
else t=lst;
if (t!=p[i]) assert(0);
}
return 0;
}