【NOIP2017】列队

题目链接

测试点1~10

观察到$q\le 500$,那我们duck只用暴力维护$500$行和最后一列。

换种说法,对行离散化,每次暴力取出数并且平移数组,时间复杂度和空间复杂度都是$O(nq)$。

测试点11~16

所有$x=1$,那就是只会用到第一行和最后一列。

思考一下,我们每次找到第$k$个数,放到最后面。

我们提取一个数出来,发现它后面的所有数的编号都会减一。

也许我们可以考虑用数据结构维护这些编号?然后每次询问就来一个二分查找,辅助数组存数值。看起来很可做。

一个想法,初始每个位置上存对应的编号,每次找到第$k$个数,对它后面进行区间减一,然后序列长度增加,把它放到最后,单点赋个值。这个线段树很好做。

还有一个思路,初始每个位置上存一,每次找到这个数,单点减一,然后序列长度增加,最后这个位置加一,每次查询前缀和。这个树状数组很好做。

所以我们选择树状数组。

代码1(80分)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define IL inline
#define RG register
#define _1 first
#define _2 second
using namespace std;
typedef long long LL;
#define RI RG int
#define RL RG LL
const int N=3e5;
const int N1=5e4;
const int Q1=500;

IL void qr(RI &x){
    x=0;    RG char ch=getchar();
    while(!isdigit(ch))    ch=getchar();
    for(;isdigit(ch);ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
}

IL void qw(RL x,RG char ch){
    RI k=0,s[13];
    if(!x)    s[k=1]=0;
    else for(;x;x/=10)    s[++k]=x%10;
    for(;k;k--)    putchar(s[k]+'0');
    putchar(ch);
}

    int n,m,q;

struct Pr{
    int x,y,d;
}a[N+3];

    int t1[Q1+3];
    
IL int bin1(RI l,RI r,RI x){
    RI mid,ans;
    while(l<=r){
        mid=(l+r)>>1;
        if(x<=t1[mid]){
            r=mid-1;    ans=mid;
        }
        else 
            l=mid+1;
        
    }
    return ans;
    
}
    
    LL p1[Q1+3][N1+3];

IL void sol1(){
    for(RI i=1;i<=q;i++)
        t1[i]=a[i].x;
    sort(t1+1,t1+q+1);
    RI mm=1;
    for(RI i=2;i<=q;i++)
    if(t1[i]!=t1[i-1])
        t1[++mm]=t1[i];
    for(RI i=1;i<=q;i++)
        a[i].x=bin1(1,mm,a[i].x);
    
    for(RI i=1;i<=mm;i++)
        for(RI j=1;j<m;j++)
            p1[i][j]=(LL)(t1[i]-1)*m+j;
    for(RI i=1;i<=n;i++)
        p1[0][i]=(LL)i*m;
    
    for(RI k=1;k<=q;k++){
        RL tmp;
        if(a[k].y==m)
            tmp=p1[0][t1[a[k].x]];
        else 
            tmp=p1[a[k].x][a[k].y];
        qw(tmp,'\n');
            
        for(RI i=a[k].y;i<m-1;i++)
            p1[a[k].x][i]=p1[a[k].x][i+1];
        p1[a[k].x][m-1]=p1[0][t1[a[k].x]];
        for(RI i=t1[a[k].x];i<n;i++)
            p1[0][i]=p1[0][i+1];
        p1[0][n]=tmp;
        
    }
    
}

IL bool check2(){
    for(RI i=1;i<=q;i++)
    if(a[i].x!=1)
        return false;
    return true;
}
    
    int k,s2[N*3+3];
    LL t2[N*3+2];
    
IL int lowbit(RI x){return x&(-x);}

IL void mdf(RI p,RI x){
    for(;p<=n+m+q;p+=lowbit(p))
        s2[p]+=x;
}

IL int qry(RI p){
    RI ret=0;
    for(;p;p-=lowbit(p))
        ret+=s2[p];
    return ret;
}

IL int bin2(RI l,RI r,RI x){
    RI mid,ans;
    while(l<=r){
        mid=(l+r)>>1;
        if(x<=qry(mid)){
            r=mid-1;    ans=mid;
        }
        else 
            l=mid+1;
        
    }
    return ans;
    
}

IL void sol2(){
    for(RI i=1;i<=n+m-1;i++)
        mdf(i,1);
    for(RI i=1;i<=m;i++)
        t2[i]=i;
    for(RI i=m+1,j=2;i<=n+m-1;i++,j++)
        t2[i]=(LL)j*m;
    
    k=n+m-1;
    for(RI i=1;i<=q;i++){
        RI pos=bin2(1,k,a[i].y);
        qw(t2[pos],'\n');
        mdf(pos,-1);
        mdf(++k,1);
        t2[k]=t2[pos];
        
    }
    
}

IL void sol3(){
    
    
}

int main(){
    qr(n);    qr(m);    qr(q);
    for(int i=1;i<=q;i++){
        qr(a[i].x);    qr(a[i].y);    a[i].d=i;
    }
    
    if(q<=500)
        sol1();
    else 
    if(check2())
        sol2();
    else 
        sol3();

    return 0;

}
View Code

测试点17~20

猜你喜欢

转载自www.cnblogs.com/Hansue/p/12984380.html