zoukankan      html  css  js  c++  java
  • 【NOIP题解】NOIP2017 TG D2T3 列队

    列队,NOIP2017 TG D2T3。

    树状数组经典题。

    题目链接:洛谷

    题意:

    Sylvia 是一个热爱学习的女孩子。

    前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。

    Sylvia 所在的方阵中有(n imes m)名学生,方阵的行数为 (n),列数为 (m)。

    为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 (1) 到 (n imes m) 编上了号码(参见后面的样例)。即:初始时,第 (i) 行第 (j) 列 的学生的编号是((i-1) imes m + j)。

    然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 (q) 件这样的离队事件。每一次离队事件可以用数对((x,y) (1 leq x leq n, 1 leq y leq m))描述,表示第 (x) 行第 (y) 列的学生离队。

    在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:

    向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 (x) 行第 (m) 列。

    向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 (n) 行第 (m) 列。
    教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 (n) 行 第 (m) 列一个空位,这时这个学生会自然地填补到这个位置。

    因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。

    注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。

    题解:

    注意到这个方阵被分成了最右侧一列,左侧(m-1)列的每一行,共(n)行这(n+1)个序列。

    操作的本质是:每次从其中一个序列中删除一个值,然后在一个序列中加入一个值。

    考虑前50%的部分分:

    q是非常小的,我们发现可以把与(x_i)无关的行排除掉,因为这些行根本不会有操作。

    然后维护每行和最后一列即可。

    那么前80%呢?

    前50%见上文。下面是后30%

    注意到所有的操作只在第一行。

    我们考虑把第一行和最后一列并在一起,形成新的序列。

    这个序列要支持:删除第(k)个元素,在末尾加入元素。

    可以使用平衡树实现,但是NOIP不考啊?

    考虑用树状数组做?怎么做?树状数组维护这一位有没有元素,(0)就是没有,(1)就是有。

    第(k)位就是前缀和等于(k)。

    删除就是(1 o 0)。

    添加就是(0 o 1),特别的,在末尾添加只要记一个末尾的指针就好了。

    怎么找第k位?

    树状数组上二分,(O(log n))。

    那么100%的数据呢?

    发现这个矩阵开始的每一位都确定。

    如果我们不维护每一行原来的元素,而是维护新加进来的元素呢?

    新加进来的元素总数不会超过(q)。

    而原来的元素可以直接得到。对于每一行,开一个树状数组来维护答案即可。

    这个做法要求离线做,先对所有询问按照(x_i)排序,然后按照60%~80%的方法维护。

    最后把每行的树状数组(合起来不超过(q)个元素),和最后一列的放在一起维护就好了。

    时间复杂度(O(qlog(q)+qlog(m+n+q)))。

    我的代码使用了指针来指向多棵树状数组,是洛谷跑的最快的!1488ms!

    代码如下:

     1 #pragma GCC optimize("O2")
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define F(i,a,b) for(int i=a;i<=b;++i)
     6 #define dF(i,a,b) for(int i=a;i>=b;--i)
     7 #define F2(i,a,b) for(int i=a;i<b;++i)
     8 #define getchar() (SS==TT&&(TT=(SS=BB)+fread(BB,1,1<<15,stdin),TT==SS)?EOF:*SS++)
     9 #define RR register
    10 char BB[1<<15],*SS=BB,*TT=BB;
    11 inline int read(){
    12     RR int x;RR bool f;RR char c;
    13     for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
    14     for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
    15     return f?-x:x;
    16 }
    17 using namespace std;
    18 int q,I[300010];
    19 long long n,m,a[300010],b[300010];
    20 inline bool cmp(int p1,int p2){return a[p1]==a[p2]?p1<p2:a[p1]<a[p2];}
    21 int h[300010],len[300010],len2[300010],bit[900010];
    22 long long arr[900010];
    23 long long Ans[300010];
    24 inline void Ins(int*array,int siz,int i,int x){for(;i<=siz;array[i]+=x,i+=i&-i);}
    25 inline int binary(int*array,int siz,int x){
    26     int l=1,r,mid,sum,ans;
    27     while(l<=siz&&array[l]<x) l<<=1, ans=l;
    28     r=l; sum=array[l>>=1];
    29     while(l<r-1){
    30         mid=l+r>>1;
    31         if(mid>siz||array[mid]+sum>=x) r=mid, ans=mid;
    32         else l=mid, sum+=array[l];
    33     } ans=r;
    34     return ans;
    35 }
    36 int stk[300001],top;
    37 int main(){
    38     n=read(), m=read(), q=read();
    39     F(i,1,q) a[i]=read(), b[i]=read(), I[i]=i;
    40     sort(I+1,I+q+1,cmp);
    41     F(i,1,m-1) Ins(bit,m-1,i,1);
    42     F(i,1,n) len[i]=m-1;
    43     F(i,1,q){
    44         if(a[I[i-1]]!=a[I[i]])
    45             while(top) Ins(bit,m-1,stk[top--],1);
    46         if(b[I[i]]>len[a[I[i]]]) continue;
    47         int pos=binary(bit,m-1,b[I[i]]);
    48         Ans[I[i]]=(a[I[i]]-1)*m+pos;
    49         Ins(bit,m-1,pos,-1);
    50         stk[++top]=pos;
    51         --len[a[I[i]]];
    52     }
    53     int iter=0;
    54     F(i,1,n){
    55         while(iter<=q&&a[I[iter]]<i) ++iter;
    56         h[i]=iter-1;
    57     }
    58     h[n+1]=q;
    59     memset(bit,0,sizeof bit);
    60     F(i,1,n) len[i]=0, len2[i]=m-1; len[n+1]=n;
    61     F(i,1,n) Ins(bit+h[n+1],n+q,i,1), arr[q+i]=i*m;
    62     F(i,1,q){
    63         if(Ans[i]){
    64             int pos=binary(bit+h[n+1],n+q,a[i]);
    65             Ins(bit+h[n+1],n+q,pos,-1);
    66             Ins(bit+h[n+1],n+q,++len[n+1],1);
    67             arr[h[n+1]+len[n+1]]=Ans[i];
    68             Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],++len[a[i]],1);
    69             arr[h[a[i]]+len[a[i]]]=arr[h[n+1]+pos];
    70             --len2[a[i]];
    71         }
    72         else{
    73             int pos=binary(bit+h[n+1],n+q,a[i]);
    74             Ins(bit+h[n+1],n+q,pos,-1);
    75             Ins(bit+h[n+1],n+q,++len[n+1],1);
    76             if(b[i]!=m){
    77                 int pos2=binary(bit+h[a[i]],h[a[i]+1]-h[a[i]],b[i]-len2[a[i]]);
    78                 Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],pos2,-1);
    79                 Ans[i]=arr[h[a[i]]+pos2];
    80                 Ins(bit+h[a[i]],h[a[i]+1]-h[a[i]],++len[a[i]],1);
    81                 arr[h[a[i]]+len[a[i]]]=arr[h[n+1]+pos];
    82             } else Ans[i]=arr[h[n+1]+pos];
    83             arr[h[n+1]+len[n+1]]=Ans[i];
    84         }
    85     }
    86     F(i,1,q) printf("%lld
    ",Ans[i]);
    87     return 0;
    88 }
    View Code
  • 相关阅读:
    测试PHP-FPM的工作流中的疑惑点
    摘要
    Centrifugo简单试用
    react-redux的基本用法
    PHP中使用ElasticSearch(二)
    PHP中使用ElasticSearch(一)
    Vue中的状态管理器
    Laravel数据库迁移
    快速搭建一个vue开发环境
    使用cURL尝试ElasticSearch
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/8214292.html
Copyright © 2011-2022 走看看