Codeforces 1737G - Ela Takes Dancing Class(平衡树)
数据结构好题。
先考虑如果 \(s_i\) 全是 \(1\) 怎么做。考虑一个非常特殊的状态:如果当前最靠左的舞蹈者跳一步就能跳到最靠右的舞蹈者的右边,那么这样的局面性质其实是非常完美的。因为容易归纳证明,这样的局面下,每一步最靠左的舞蹈者跳一步都能跳到最靠右的舞蹈者的右边,这样一来,如果维护出了初始局面下 \(n\) 个人坐标排序后的结果,那么就可以 \(O(1)\) 地算出 \(k\) 轮以后某个人的位置,进而求出答案。
考虑更一般的情况,如果第一步中第 \(1\) 个人恰好跳过了第 \(x\) 个人,那么我们就称当前前 \(x\) 个人形成了一个“完美局面”。那么这个过程显然是,随着时间线的推移,\(x\) 不断增加。由于 \(x\) 的变化是 \(O(n)\) 的,所以我们只要知道,如果当前前 \(x\) 个人形成了“完美局面”,至少需要多少轮后第一个人能够跳过第 \(x+1\) 个人即可。这一部分我们二分答案 \(mid\)。先假设前 \(mid\) 轮没有跳过第 \(x+1\) 个人,算一下 \(mid\) 轮后最后一个人的位置,如果超过第 \(x+1\) 个人当前的位置说明 \(mid\) 轮内 \(x\) 已经增加了,因为如果跳过了 \(x+1\) 那么 \(mid\) 轮后最后一个人的位置肯定比我们计算出的值大。使用平衡树维护即可。对于一个完美局面而言,进行 \(mid\) 轮后的结果对顺序的影响实际上是将一个前缀 cyclic shift。除此之外还需要实现区间加与查询第 \(k\) 小的值的位置。这是容易用平衡树维护的。
接下来考虑有 \(s_i=0\) 的情况,其实也比较好办,对于 \(s_i=0\) 的舞蹈者,先当他是可以移动的,然后计算下最早什么时候会出现“坐标最小的舞蹈者是不可移动”的情况,如果这段时间内 \(x\) 没有增加,就暴力跳到那一时刻然后将最小的元素从平衡树里删掉即可。
时间复杂度 \(n\log^2n\)。
const int MAXN=1e5;
const int INF=0x3f3f3f3f;
const ll INFll=0x3f3f3f3f3f3f3f3fll;
int n,d,qu,A[MAXN+5],B[MAXN+5];ll st[MAXN+5],res[MAXN+5];int st_cnt;
struct qry{
int t,k,id;
friend bool operator <(const qry &X,const qry &Y){
return X.t<Y.t;
}
}q[MAXN+5];
mt19937 rng(time(0));
struct node{int ch[2],key,siz;ll pos,lz;int typ,has;}s[MAXN+5];
int ncnt,rt;
int nwnd(int x,int y){
++ncnt;s[ncnt].siz=1;s[ncnt].key=rng();
s[ncnt].pos=x;s[ncnt].typ=s[ncnt].has=!y;
return ncnt;
}
void tag(int k,ll v){if(k)s[k].pos+=v,s[k].lz+=v;}
void pushdown(int k){
if(s[k].lz){
if(s[k].ch[0])tag(s[k].ch[0],s[k].lz);
if(s[k].ch[1])tag(s[k].ch[1],s[k].lz);
s[k].lz=0;
}
}
void pushup(int k){
s[k].has=s[s[k].ch[0]].has|s[s[k].ch[1]].has|s[k].typ;
s[k].siz=s[s[k].ch[0]].siz+s[s[k].ch[1]].siz+1;
}
void split(int k,int sz,int &a,int &b){
if(!k)return a=b=0,void();pushdown(k);
if(sz<=s[s[k].ch[0]].siz)b=k,split(s[k].ch[0],sz,a,s[k].ch[0]),pushup(k);
else a=k,split(s[k].ch[1],sz-s[s[k].ch[0]].siz-1,s[k].ch[1],b),pushup(k);
}
int merge(int a,int b){
if(!a||!b)return a+b;pushdown(a);pushdown(b);
if(s[a].key<s[b].key)return s[a].ch[1]=merge(s[a].ch[1],b),pushup(a),a;
else return s[b].ch[0]=merge(a,s[b].ch[0]),pushup(b),b;
}
int get_fst(int k){
if(!s[k].has)return INF;if(!k)return 0;
if(s[s[k].ch[0]].has)return get_fst(s[k].ch[0]);
else if(s[k].typ)return s[s[k].ch[0]].siz+1;
else return s[s[k].ch[0]].siz+1+get_fst(s[k].ch[1]);
}
ll get_kth(int x){
int k1,k2,p;split(rt,x,k1,k2);p=k1;
while(s[p].ch[1])pushdown(p),p=s[p].ch[1];
ll res=s[p].pos;rt=merge(k1,k2);return res;
}
int get_cnt(){
int L=1,R=s[rt].siz,p=0;ll v1=get_kth(1);
while(L<=R){
int mid=L+R>>1;
if(get_kth(mid)<=v1+d+mid-2)p=mid,L=mid+1;
else R=mid-1;
}return p;
}
ll get_nxt(int x,int stp){
int ps=(stp-1)%x+1;
return get_kth(ps)+1ll*((stp-1)/x+1)*(d+x-1);
}
int main(){
scanf("%d%d%d",&n,&d,&qu);
for(int i=1;i<=n;i++)scanf("%d",&A[i]);
for(int i=1;i<=n;i++)scanf("%1d",&B[i]);
for(int i=1;i<=qu;i++)scanf("%d%d",&q[i].t,&q[i].k),q[i].id=i;
for(int i=1;i<=n;i++)rt=merge(rt,nwnd(A[i],B[i]));
sort(q+1,q+qu+1);int cur=1,tim=0;
pii pre=mp(0,0);
while(cur<=qu){
int pos=get_fst(rt);
if(pos==1){
int k1,k2;split(rt,1,k1,k2);rt=k2;
st[++st_cnt]=s[k1].pos;continue;
}
int x=get_cnt();ll pos_x=(x==s[rt].siz)?INFll:get_kth(x+1);
int L=1,R=(pos<=x)?(pos-1):INF,p=0;
while(L<=R){
int mid=L+R>>1;
if(get_nxt(x,mid)<pos_x)p=mid,L=mid+1;
else R=mid-1;
}
while(cur<=qu){
if(q[cur].t>tim+p)break;
if(q[cur].k<=st_cnt)res[q[cur].id]=st[q[cur].k];
else{
int _k=q[cur].k-st_cnt;
if(_k>x)res[q[cur].id]=get_kth(_k);
else{
int ps=(_k+q[cur].t-tim-1)%x+1;
int cnt=(q[cur].t-tim)/x+(ps<=(q[cur].t-tim)%x);
res[q[cur].id]=get_kth(ps)+1ll*cnt*(d+x-1);
}
}
++cur;
}
int k1,k2,k3;split(rt,x,k1,k3);split(k1,p%x,k1,k2);
tag(k1,1ll*(d+x-1)*(p/x+1));tag(k2,1ll*(d+x-1)*(p/x));
rt=merge(merge(k2,k1),k3);
tim+=p;
}
for(int i=1;i<=qu;i++)printf("%lld\n",res[i]);
return 0;
}

浙公网安备 33010602011771号