显然倒着做更方便,显然每个位置的后继可选择区间可以均摊 \(O(1)\) 搞出来,显然每个后缀的答案只由这个位置和它的后继后缀决定,关键在于如何给已经求出的后继后缀排序。
容易想到平衡树计算排名,但是无法实时更新,因此难以使用平衡树自身性质更新自己。但是假如我们给区间打上标记后,每次查询通过每个节点 \(O(\log n)\) 跳父亲得到,正确性就可以保证。注意后置父亲修改以保证跳父亲的正确性。
总时间复杂度 \(O(n\log^2n)\)。
#include<bits/stdc++.h>
#define ls(x) trp[x].ls
#define rs(x) trp[x].rs
#define sz(x) trp[x].sz
#define rk(x) trp[x].rk
#define fl(x) trp[x].fl
#define fa(x) trp[x].fa
#define num(x) trp[x].num
#define val(x) trp[x].val
using namespace std;
const int N=2e5+5;
struct suf{int fs,ls;};
struct fhq{int ls,rs,sz,rk,num,fl,fa;suf val;
}trp[N];int t,n,rt,a[N],nx[N],lst[N],zz;
inline int getnum(int x){int re=num(x);x=fa(x);while(x) re+=fl(x),x=fa(x);return re;
}inline bool operator<(suf x,suf y){return x.fs!=y.fs?x.fs<y.fs:getnum(x.ls)<getnum(y.ls);
}inline int mk(int cc,suf vl,int siz){return trp[cc]={0,0,1,rand(),siz+1,0,0,vl},cc;
}namespace FHQ{inline void push_up(int x){sz(x)=sz(ls(x))+sz(rs(x))+1;}inline void down(int x,int k){fl(x)+=k,num(x)+=k;}inline void push_down(int x){down(ls(x),fl(x)),down(rs(x),fl(x)),fl(x)=0;}inline void split(int x,suf v,int &a,int &b,int af,int bf){if(!x){a=b=0;return;}push_down(x);if(v<val(x)) split(ls(x),v,a,ls(b=x),af,x),fa(x)=bf;else split(rs(x),v,rs(a=x),b,x,bf),fa(x)=af;push_up(x);}inline int merge(int x,int y){if(!x||!y) return x|y;push_down(x),push_down(y);if(rk(x)<rk(y)) return rs(x)=merge(rs(x),y),fa(rs(x))=x,push_up(x),x;return ls(y)=merge(x,ls(y)),fa(ls(y))=y,push_up(y),y;}
}namespace seg{int id[N<<2];inline int kmin(int x,int y){if(x<zz) return y;return getnum(x)<getnum(y)?x:y;}inline void build(int x,int l,int r){id[x]=l;if(l==r) return;int mid=(l+r)>>1;build(x<<1,l,mid);build(x<<1|1,mid+1,r);}inline void chg(int x,int l,int r,int k){if(l==r) return;int mid=(l+r)>>1;if(k<=mid) chg(x<<1,l,mid,k);else chg(x<<1|1,mid+1,r,k);id[x]=kmin(id[x<<1],id[x<<1|1]);}inline int minn(int x,int l,int r,int L,int R){if(L<=l&&r<=R) return id[x];int mid=(l+r)>>1,re=0;if(L<=mid) re=minn(x<<1,l,mid,L,R);if(R>mid) re=kmin(re,minn(x<<1|1,mid+1,r,L,R));return re;}
}inline void solve(){cin>>n,rt=mk(zz=++n,{-1,0},0),a[n]=-1;seg::build(1,1,n),seg::chg(1,1,n,n);for(int i=1;i<n;i++) cin>>a[i],lst[i]=nx[i]=0;for(int i=n-1;i;i--){nx[i]=i+1;while(nx[i]<n&&(a[i]|a[nx[i]])==a[i]) nx[i]=nx[nx[i]];lst[i]=seg::minn(1,1,n,i+1,nx[i]);int ac,bc;FHQ::split(rt,{a[i],lst[i]},ac,bc,0,0),FHQ::down(bc,1);ac=FHQ::merge(ac,mk(i,{a[i],lst[i]},sz(ac)));fa(ac)=0,rt=FHQ::merge(ac,bc),fa(rt)=0;zz=i,seg::chg(1,1,n,i);}for(int i=1;i<n;i=lst[i]) cout<<a[i]<<" ";cout<<"\n";
}int main(){freopen("min.in","r",stdin);freopen("min.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);srand(time(0)),cin>>t;while(t--) solve();return 0;
}