loj#2319. 「NOIP2017」列隊(線段樹+二分)

題面在這裏
突然來填這個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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章