loj#2319. 「NOIP2017」列队(线段树+二分)

10 篇文章 0 订阅
9 篇文章 0 订阅

题面在这里
突然来填这个noip坑。顺便记一下一个可怕的错误。

做法

动态开点线段树+二分即可。
主要思想就是将题意转化为删除+插入操作,删除打1的标记。

代码

=> 用 while (q--) 的时候一定要留心看下下面有没有用到q =_=

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
#define ld long double
#define inf 1000000000
using namespace std;
ll read(){
    char ch=getchar(); ll x=0; int op=1;
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
    for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*op;
}
#define N 300005
#define M 8000005
int siz[M],pos[N],ls[M],rs[M],rt[N],tot,loc; ll n,m,q,val[M];
ll getkth(int &k,int l,int r,int now,int &loc){
    if (!k) k=++tot;
    if (l==r){ siz[k]=1; loc=l; return val[k]; }
    int mid=l+r>>1; ll ret;
    if (mid-l+1-siz[ls[k]]>=now) ret=getkth(ls[k],l,mid,now,loc);
    else ret=getkth(rs[k],mid+1,r,now-(mid-l+1-siz[ls[k]]),loc);
    siz[k]=siz[ls[k]]+siz[rs[k]]; return ret;
}
void ins(int &k,int l,int r,int x,ll y){
    if (!k) k=++tot;
    if (l==r){ val[k]=y; return; }
    int mid=l+r>>1;
    if (x<=mid) ins(ls[k],l,mid,x,y); else ins(rs[k],mid+1,r,x,y);
    siz[k]=siz[ls[k]]+siz[rs[k]];
}
int main(){
    n=read(),m=read(),q=read();
    rep (i,1,n) pos[i]=m-1; pos[n+1]=n;
    rep (i,1,q){//傻子如我写成了while (q--)。
        int x=read(),y=read();//1表示删除。
        if (y==m){//第y个未删除的位置
            ll tmp=getkth(rt[n+1],1,n+q,x,loc);
            if (loc<=n) tmp=loc*m;
            printf("%lld\n",tmp);
            ins(rt[n+1],1,n+q,++pos[n+1],tmp);
        } else{
            ll tmp=getkth(rt[x],1,m+q,y,loc);
            if (loc<m) tmp=(x-1)*m+loc;
            printf("%lld\n",tmp);
            ins(rt[n+1],1,n+q,++pos[n+1],tmp);
            tmp=getkth(rt[n+1],1,n+q,x,loc);
            if (loc<=n) tmp=loc*m;
            ins(rt[x],1,m+q,++pos[x],tmp);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值