专栏文章

题解:P10440 [JOIST 2024] 环岛旅行 / Island Hopping

P10440题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minrimvi
此快照首次捕获于
2025/12/02 07:10
3 个月前
此快照最后确认于
2025/12/02 07:10
3 个月前
查看原文
考虑以 11 为根。
如果确定了 i=1i=1,令 kk 取遍 [1,n1][1,n-1],那么最后的答案一定是从 11 开始的 bfs 序。
一个比较好的想法是确定每一个点的父亲。
考虑 bfs 序与一个点的父亲有什么性质。可以发现“uuvv 的父亲”是“uu 的 bfs 序在 vv 之前”的充分不必要条件。
考虑什么时候它必要。当然,如果 uuvv 相邻,那么它一定是必要的。
所以可以从 22 号点往后依次确定父亲了。考虑当前搜到的是点 ii
  • 如果 ii 号点的父亲已经被确定了就跳过;
  • 否则,从小到大取遍 k[1,n1]k \in [1,n-1],直到能够确定 ii 号点的父亲为止,即 query(i,k) 得到的 bfs 序比 ii 号点的 bfs 序要小。可以证明,跳出循环之前搜到的点一定与 ii 相邻
  • 对于失败的点,实际上可以确定 ii 是这些点的父亲。很简单,因为此时这些点的 bfs 序大于 ii 的 bfs 序。
所以每一个父亲-儿子关系只会查询有且仅有一次,查询的次数为确定 bfs 序与确定父亲-儿子关系的查询次数之和 2n22n-2,可以通过。
CPP
#include<bits/stdc++.h>
using namespace std;
int query(int,int);
void answer(int,int);
int main();
int fa[1005],bfn[1005],nfb[1005];
void solve(int N,int L){
    for(int i=1;i<=N-1;i++){
        int x=query(1,i);
        bfn[x]=i;
        nfb[i]=x;
    }
    for(int i=1;i<=N-1;i++){
        if(fa[nfb[i]])continue;
        for(int k=1;k<=N-1;k++){
            int x=query(nfb[i],k);
            if(bfn[x]<i){
                fa[nfb[i]]=x;
                break;
            }else{
                fa[x]=nfb[i];
            }
        }
    }
    for(int i=2;i<=N;i++){
        answer(fa[i],i);
    }
}
// int query(int v,int k){
//     cout<<"? "<<v<<" "<<k<<"\n";
//     int x;
//     cin>>x;
//     return x;
// }
// void answer(int x,int y){
//     cout<<"! "<<x<<" "<<y<<"\n";
// }
// int main(){
//     int N,L;
//     cin>>N>>L;
//     solve(N,L);
//     return 0;
// }

评论

0 条评论,欢迎与作者交流。

正在加载评论...