有趣的交互题(交互题都挺有意思的)
增量法构造
考虑加入了前i个叶子
那么树是前i个叶子构成的虚树!
最后n个叶子构成的虚树就是答案!
怎样确定第i+1个叶子的位置?
用点分治“二分”!
每次找到当前连通块的重心rt,注意rt不能是叶子
维护rt的两个儿子,父亲,两个儿子内部随意一个叶子has[0],has[1]
用has[0],has[1],i+1进行ask,X,Y,Z唯一确定一个方向:fa、rson,lson
递归进去二分。
边界:
1.往fa走没有fa,新建
2.往fa、son已经vis了,这个边上长出一个点和一个叶子来
3.当前点是叶子,新建节点,叶子和i+1连在下面。
询问次数O(nlogn)
复杂度O(n^2)(每次现找重心,只递归一边。)
注意:
1.点分治找到rt之后再dfs才是真正size。。
2.rt和进入点x不能弄混了。。
Code
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define mk(a,b) make_pair(a,b) #define numb (ch^'0') #define pb push_back #define solid const auto & #define enter cout<<endl #define pii pair<int,int> using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);} template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar(' ');} namespace Modulo{ const int mod=998244353; int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;} void inc(int &x,int y){x=ad(x,y);} int mul(int x,int y){return (ll)x*y%mod;} void inc2(int &x,int y){x=mul(x,y);} int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;} } //using namespace Modulo; namespace Miracle{ const int N=2005; int n; char s[233]; int fa[N],ch[N][2],has[N][2];//has a leaf int tot; int ask(int a,int b,int c){ printf("%d %d %d ",a,b,c); fflush(stdout); scanf("%s",s+1); return (s[1]-'X'); } bool vis[N]; int rt,sz[N]; int nowsz; void dfs(int x,int od){ if(!x) return; // cout<<" x "<<x<<" od "<<od<<" "<<fa[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<" visf "<<vis[fa[x]]<<" "<<(fa[x]!=od)<<endl; sz[x]=1; int mx=0,now; if(!vis[fa[x]]&&fa[x]!=od) dfs(fa[x],x),mx=max(mx,sz[fa[x]]),sz[x]+=sz[fa[x]]; if(!vis[ch[x][0]]&&ch[x][0]!=od) dfs(ch[x][0],x),mx=max(mx,sz[ch[x][0]]),sz[x]+=sz[ch[x][0]]; if(!vis[ch[x][1]]&&ch[x][1]!=od) dfs(ch[x][1],x),mx=max(mx,sz[ch[x][1]]),sz[x]+=sz[ch[x][1]]; if((ch[x][0]||ch[x][1])&&(max(mx,nowsz-sz[x])<=nowsz/2)) rt=x; } void dfs2(int x,int od){ if(!x) return; // cout<<" x "<<x<<" od "<<od<<" "<<fa[x]<<" "<<ch[x][0]<<" "<<ch[x][1]<<" visf "<<vis[fa[x]]<<" "<<(fa[x]!=od)<<endl; sz[x]=1; if(!vis[fa[x]]&&fa[x]!=od) dfs2(fa[x],x),sz[x]+=sz[fa[x]]; if(!vis[ch[x][0]]&&ch[x][0]!=od) dfs2(ch[x][0],x),sz[x]+=sz[ch[x][0]]; if(!vis[ch[x][1]]&&ch[x][1]!=od) dfs2(ch[x][1],x),sz[x]+=sz[ch[x][1]]; } void fin(int x,int id){ // cout<<" fin "<<x<<" nowsz "<<nowsz<<endl; if(!ch[x][0]&&!ch[x][1]){//leaf // cout<<" leaf "<<endl; ++tot; int d=ch[fa[x]][1]==x; ch[tot][0]=x;ch[tot][1]=id;fa[tot]=fa[x];ch[fa[x]][d]=tot; fa[x]=tot;fa[id]=tot; has[tot][0]=x;has[tot][1]=id; return ; } rt=0; dfs(x,0); x=rt; dfs2(rt,0); // cout<<" rt "<<rt<<" has "<<has[rt][0]<<" "<<has[rt][1]<<endl; int bc=ask(has[rt][0],has[rt][1],id); vis[rt]=1; if(bc==0){ if(fa[x]){ if(vis[fa[x]]){ int y=fa[x]; int d=ch[y][1]==x; ch[y][d]=++tot; fa[tot]=y; ch[tot][d]=x;fa[x]=tot; ch[tot][d^1]=id; fa[id]=tot; has[tot][d]=has[x][0]; has[tot][d^1]=id; }else{ nowsz=sz[fa[x]]; fin(fa[x],id); } }else{ // cout<<" nofa "<<endl; fa[x]=++tot; ch[tot][0]=x; ch[tot][1]=id; has[tot][0]=has[x][0]; has[tot][1]=id; fa[id]=tot; } }else { int p; if(bc==1) p=1; else p=0; if(ch[x][p]){ int z=ch[x][p]; // cout<<" z "<<z<<endl; if(vis[z]){ ++tot; ch[x][p]=tot;fa[tot]=x; ch[tot][p]=z;fa[z]=tot; ch[tot][p^1]=id;fa[id]=tot; has[tot][p^1]=id; has[tot][p]=has[z][0]; }else{ nowsz=sz[z]; fin(z,id); } }else{ assert(-1>0); } } } int main(){ rd(n); tot=n; ++tot; has[tot][0]=ch[tot][0]=1;fa[1]=tot; has[tot][1]=ch[tot][1]=2;fa[2]=tot; for(reg i=3;i<=n;++i){ // cout<<"ii ----------------------- "<<i<<endl; memset(vis,0,sizeof vis); memset(sz,0,sizeof sz); // for(reg j=1;j<i;++j) vis[j]=1; nowsz=2*(i-1)-1; // cout<<" vis[55] "<<vis[55]<<endl; fin(tot,i); // for(reg i=1;i<=tot;++i){ // cout<<i<<" : fa "<<fa[i]<<" ls "<<ch[i][0]<<" rs "<<ch[i][1]<<" hasls "<<has[i][0]<<" hasrs "<<has[i][1]<<endl; // } } // prt(fa,1,tot); printf("-1 "); for(reg i=1;i<=tot;++i){ if(!fa[i]) fa[i]=-1; ot(fa[i]); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* */
交互题都是要找到一个方向去构造的
比如这个就是增量构造
10*n,类似nlogn,二分?
考虑定位,发现点分治最合适了。