似乎是noip2017d2t3的一个部分分。用splay的话当然非常裸,但说不定会被卡常。可以发现序列中数的(环上)相对位置是不变的,考虑造一棵权值线段树维护权值区间内还有多少个数留在序列中,每次在线段树上二分即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 700010 int n,L[N<<2],R[N<<2],size[N<<2],p=1; void build(int k,int l,int r) { L[k]=l,R[k]=r;size[k]=r-l+1; if (l==r) return; int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); } void dec(int k,int p) { size[k]--; if (L[k]==R[k]) return; if (p<=(L[k]+R[k]>>1)) dec(k<<1,p); else dec(k<<1|1,p); } int querys(int k,int l,int r) { if (l>r) return 0; if (L[k]==l&&R[k]==r) return size[k]; int mid=L[k]+R[k]>>1; if (r<=mid) return querys(k<<1,l,r); else if (l>mid) return querys(k<<1|1,l,r); else return querys(k<<1,l,mid)+querys(k<<1|1,mid+1,r); } int find(int k,int x) { if (L[k]==R[k]) return L[k]; int mid=L[k]+R[k]>>1; if (size[k<<1]>=x) return find(k<<1,x); else return find(k<<1|1,x-size[k<<1]); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4415.in","r",stdin); freopen("bzoj4415.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(); build(1,1,n); for (int i=1;i<=n;i++) { int x=read()%(n-i+1)+1; int s=querys(1,p,n); if (s>=x) p=find(1,querys(1,1,p-1)+x); else x-=s,p=find(1,x); dec(1,p); printf("%d ",p); } return 0; }