CF1370F The Hidden Pair 題解
阿新 • • 發佈:2021-10-29
Link.
Codeforces F1
Codeforces F2
Luogu F1
Luogu F2
Description.
樹上互動,有兩個標記點。
每次你詢問一個點集,每次返回這個點集中到兩標記距離和最小的點和這個距離和。
F1 \(14\) F2 \(11\) 次內詢問出兩個標記點。
Solution.
首先,什麼資訊都沒有的情況下肯定很困難。
我們先詢問全集,以返回的最小點為根,這樣兩個標記點就在兩棵子樹內,同時知道了鏈長。
考慮 binary search,二分較大目標點的深度。
每次可以把這層所有點拿出來問。
判斷 dis 是不是和鏈長相等來判斷較深的那個點是不是在這個深度以下。
這樣需要 \(1+\log n+1 \approx 12\)
考慮較深那個點的值域,發現 \(\in[\frac {dis}2,dis]\),然後就節約了二分的一次。
Coding.
點選檢視程式碼
//Coded by leapfrog on 2021.10.29 {{{ //是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了 #include<bits/stdc++.h> using namespace std;typedef long long ll; template<typename T>inline void read(T &x) { x=0;char c=getchar(),f=0; for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1; for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48); f?x=-x:x; } template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}} const int N=1005;int as[N],at,dis;vector<int>d[N]; struct edge{int to,nxt;}e[N<<1];int n,et,head[N],rx,fg[N]; inline void adde(int x,int y) {e[++et]=(edge){y,head[x]},head[x]=et;} inline pair<int,int> ask() { printf("? %d ",at);for(int i=1;i<=at;i++) printf("%d%c",as[i],i==at?'\n':' '); fflush(stdout);int u,v;read(u,v);return make_pair(u,v); } inline void answer(int x,int y) { printf("! %d %d\n",x,y),fflush(stdout);char ch[10]; scanf("%s",ch);if(*ch=='I') exit(0); } inline void dfs0(int x,int fa,int dep,int rt) { d[dep].push_back(x),fg[x]=rt; for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs0(e[i].to,x,dep+1,rt); } inline char check(int w) { if(d[w].empty()) return 0;else at=d[w].size(); for(int i=1;i<=at;i++) as[i]=d[w][i-1]; pair<int,int>q=ask();if(q.second==dis) return rx=q.first,1;else return 0; } inline void solve() { read(n),et=0;for(int i=1;i<=n;i++) head[i]=fg[i]=0; for(int i=1,x,y;i<n;i++) read(x,y),adde(x,y),adde(y,x); at=n;for(int i=1;i<=n;i++) as[i]=i,d[i].clear(); pair<int,int>q=ask();int rt=q.first;dis=q.second; int l=(dis+1)/2,r=dis+1,rs=r;d[1].push_back(rt); for(int i=head[rt];i;i=e[i].nxt) dfs0(e[i].to,rt,2,e[i].to); while(l<=r) {int md=(l+r)>>1;if(check(md)) rs=md,l=md+1;else r=md-1;} int ds=dis-rs+2;at=0; for(size_t i=0;i<d[ds].size();i++) if(fg[d[ds][i]]^fg[rx]) as[++at]=d[ds][i]; q=ask(),answer(rx,q.first); } int main() {int Ca;for(read(Ca);Ca--;) solve();return 0;}