qzezoj 1588 队列重构(加强版)
题面传送门
\(90\)分做法见这里
正解是线段树+分治。
我们尝试在线段树上跑分治,则维护线段树每个节点的有几个位置没被选两边跑分治就好了。
代码实现:
#include<cstdio>
using namespace std;
int n,sum[4000039],now[1000039],a[1000039],b[1000039];
inline void read(register int &x) {
x=0;register char s=getchar();
while(s<'0'||s>'9')s=getchar();
while(s>='0'&&s<='9')x=(x<<3)+(x<<1)+(s^48),s=getchar();
}
inline void print(register int x) {
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline int jianshu(register int l,register int r,register int now){
if(l==r)return sum[now]=1;
register int m=(l+r)>>1;
return sum[now]=jianshu(l,m,now<<1)+jianshu(m+1,r,now<<1|1);
}
int main(){
register int i,l,r,nows,x,y,ans;
read(n);
for(i=1;i<=n;i++) read(x),read(y),now[x]=y;
jianshu(1,n,1);
for(i=1;i<=n;i++){
x=now[i]+1;
l=1;r=n;nows=1;
while(l!=r){
if(sum[nows<<1]>=x) r=(l+r)>>1,nows<<=1;
else x-=sum[nows<<1],l=((l+r)>>1)+1,nows=nows<<1|1;
}
ans=l;
a[ans]=i;b[ans]=now[i];
l=1;r=n;nows=1;
while(l!=r){
sum[nows]--;
if(ans<=((l+r)>>1)) r=(l+r)>>1,nows<<=1;
else l=((l+r)>>1)+1,nows=nows<<1|1;
}
sum[nows]--;
}
for(i=1;i<=n;i++) print(a[i]),putchar(' '),print(b[i]),putchar('\n');
}

浙公网安备 33010602011771号