zoukankan      html  css  js  c++  java
  • 【NOIP2017】列队

    题目链接

    测试点1~10

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

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

    测试点11~16

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

    思考一下,我们每次找到第$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,'
    ');
                
            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],'
    ');
            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

    首先,将最后一列单独拿出来,用代码1中的算法维护。

    然后发现,操作可以分为两类:

    1. $y=m$,直接在最后一列上维护;
    2. $y<m$,每行的所有操作放到一起,看起来也是类似的问题。

    那么,假如我们把最后一列单独拿走,剩下的第$i$行延长$c_i$格($c_i$表示第$i$行的操作数),然后我们发现可以对所有行以及最后一列分别用树状数组维护。

    注意到不能开$n+1$个树状数组来在线做,不然会爆空间。

    如果每次单独拿出同一行的操作,发现也不能得到答案,因为存在时间跨度,最后一列的数值会流通,我们无从得知加入每一行的数值是哪些。

    但是我们发现,单独拿出来做,虽然得不到数值关系,但是可以得到位置关系。也即,我们可以预处理出对于每行,扩容后的数列里,每次操作对应的位置。

    扩容后的数列分为两部分:

    1. 下标小于$m$的,这部分是“原生”数值,可以直接算得。注意会爆int。
    2. 下标大于等于$m$的,设它的下标为$y$,那么它就是在第$y-m+1$次操作该行时加入的。考虑到$c_i$的总和是$q$,我们可以开$n$个vector来存。注意vector的下标是从0开始的,所以$y$下标的询问在vector中的下标是$y-m$。

    上面的差不多就是主要内容了。再来理清一下思路:

    1. 依次对于$x$相同的询问,利用树状数组,按照时间顺序预处理出在“扩容数列”里的下标(询问$(x,m)$的标记为操作最后一列然后不参与这部分的处理);
    2. 利用树状数组维护最后一列的流动情况,然后每次按时间顺序对询问分情况处理:答案怎么算,需不需要插入vector等等。

    再补充一个细节:预处理的时候,每次记录修改树状数组的位置,每新开一行就按照记录复原修改,用总共$O(q)$的时间来完成每行的初始化。

    代码2(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #define IL inline
    #define RG register
    using namespace std;
    typedef long long LL;
    typedef unsigned int UI;
    #define RI RG int
    #define RC RG char
    #define RL RG LL
    #define RU RG UI
    const int N=3e5;
    
        int n,m,q;
    
    struct Qry{
        int x,y,d;
    }a[N+3];
    
    IL bool cmp1(Qry A,Qry B){
        return A.x==B.x?A.d<B.d:A.x<B.x;
    }
    
    IL bool cmp2(Qry A,Qry B){
        return A.d<B.d;
    }
    
        int lim,s[N*2+3];
    
    IL int lowbit(RI x){
        return x&(-x);
    }
    
    IL void mdf(RI p,RI x){
        for(;p<=lim;p+=lowbit(p))
            s[p]+=x;
    }
    
    IL int qry(RI p){
        RI ret=0;
        for(;p;p-=lowbit(p))
            ret+=s[p];
        return ret;
        
    }
    
    IL int sol(RI x){
        RI l=1,r=lim,ans,mid;
        while(l<=r){
            mid=(l+r)>>1;
            if(x<=qry(mid)){
                r=mid-1;    ans=mid;
            }
            else 
                l=mid+1;
            
        }
        return ans;
        
    }
    
        vector<int>rec;
        vector<LL>t[N+3];
        LL ans[N*2+3];
    
    int main(){
        scanf("%d%d%d",&n,&m,&q);
        for(RI i=1;i<=q;i++){
            scanf("%d%d",&a[i].x,&a[i].y);
            a[i].d=i;
            
        }
        
        sort(a+1,a+q+1,cmp1);
        lim=m+q;
        for(RI i=1;i<m;i++)
            mdf(i,1);
        for(RI i=1,p=m-1,pos;i<=q;i++){
            if(a[i].x!=a[i-1].x){
                for(UI j=0;j<rec.size();j++)
                    mdf(rec[j],1);
                while(p>=m){
                    mdf(p,-1);    p--;
                }
                rec.clear();
                
            }
            
            if(a[i].y==m){
                a[i].y=-1;
                continue;
                
            }
            pos=sol(a[i].y);
            rec.push_back(pos);
            mdf(pos,-1);
            mdf(++p,1);
            a[i].y=pos;
            
        }
        
        sort(a+1,a+q+1,cmp2);
        memset(s,0,(m+q+1)*sizeof(int));
        lim=n+q;
        for(RI i=1;i<=n;i++){
            mdf(i,1);
            ans[i]=(LL)i*m;
            
        }
        
        RL tmp;
        for(RI i=1,p=n,pos;i<=q;i++)
        if(a[i].y==-1){
            pos=sol(a[i].x);
            mdf(pos,-1);
            
            tmp=ans[pos];
            
            ans[++p]=tmp;
            mdf(p,1);
            printf("%lld
    ",tmp);
            
        }
        else {
            pos=sol(a[i].x);
            mdf(pos,-1);
            
            if(a[i].y<m)
                tmp=(LL)(a[i].x-1)*m+a[i].y;
            else 
                tmp=t[a[i].x][a[i].y-m];
            t[a[i].x].push_back(ans[pos]);
            
            ans[++p]=tmp;
            mdf(p,1);
            printf("%lld
    ",tmp);
            
        }
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    20155325 2016-2017-2 《Java程序设计》课程总结
    实验五 网络编程与安全
    2017-2018-1 20155314 20155323   实验一  开发环境的熟悉
    2017-2018-1 20155323 《信息安全系统设计基础》第4周学习总结
    2017-2018-1 20155323 《信息安全系统设计基础》第3周学习总结
    # 2017-2018-1 20155323 《信息安全系统设计基础》第2周学习总结
    2017-2018-1 20155323 《信息安全系统设计基础》第1周学习总结
    C语言复习20170826
    C语言复习20170821
    C语言复习20170805
  • 原文地址:https://www.cnblogs.com/Hansue/p/12984380.html
Copyright © 2011-2022 走看看