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

    题面

    分析

    知名数据结构题。

    今天拿给我做我还是会毫不犹豫地敲个50的暴力吧,因为细节其实是很多的。

    考虑维护n+1棵线段树,前n棵维护n排的m-1个人,最后一棵维护最后一列的n个人

    每次坐标为(x,y)的一个人离开队伍,相当于把这个人取出来放到最后一列的最后一个位置。

    然后就这样就完了吗?原来第x行的最后一个位置,这时应该成为了倒数第二个位置,换言之,它本来不在第x棵线段树的维护范围内,现在它进入了,不能忘记把它加进去。

    显然数组开不下,考虑动态开点,初始每棵树仅一个结点,其权值表示有多少个点。在我们查询或者插入需要访问用到一个结点时,再加入这个结点,并给它赋上信息。

    代码

    1. #include<bits/stdc++.h>  
    2. using namespace std;  
    3. #define M 300030  
    4. #define N 8000080  
    5. #define mid (l+r>>1)  
    6. #define ll long long  
    7. int n,m,q,w,cnt,now;  
    8. int root[M],t[N],lc[N],rc[N],pos[N];  
    9. ll out,id[N];  
    10. inline int cal(int l,int r)  
    11. {//查询这段区间的结点数   
    12.     if(now<=n)  
    13.     {  
    14.         if(r<m)return r-l+1;  
    15.         else if(l<m) return m-1-l+1;  
    16.         else return 0;  
    17.     }  
    18.     else  
    19.     {  
    20.         if(r<=n)return r-l+1;  
    21.         else if(l<=n) return n-l+1;  
    22.         else return 0;  
    23.     }  
    24. }  
    25. inline void query(int &p,int l,int r)  
    26. {  
    27.       
    28.     if(!p)p=++cnt,t[p]=cal(l,r);  
    29.     if(l==r)  
    30.     {  
    31.         t[p]=0;  
    32.         if(!id[p])out=(now<=n)?(ll)(now-1)*(ll)m+l:(ll)m*(ll)l;  
    33.         else out=id[p];  
    34.         return;  
    35.     }  
    36.     else  
    37.     {  
    38.         t[p]--;//删除一个结点   
    39.         int left=lc[p]?t[lc[p]]:cal(l,mid);//个数是否达到要查的数量    
    40.         if(w<=left)query(lc[p],l,mid);//没达到,往左找   
    41.         else w-=left,query(rc[p],mid+1,r);//超过了,在右边找   
    42.     }  
    43. }  
    44.   
    45. inline void update(int &p,int l,int r)  
    46. {  
    47.     if(!p)p=++cnt,t[p]=cal(l,r);  
    48.     if(l==r){t[p]=1;id[p]=out;return ;}  
    49.     ++t[p];//加入一个结点   
    50.     if(w<=mid)update(lc[p],l,mid);  
    51.     else update(rc[p],mid+1,r);  
    52. }  
    53.   
    54. int main()  
    55. {  
    56.     scanf("%d%d%d",&n,&m,&q);  
    57.     for(int i=1;i<=n;i++)root[i]=++cnt,t[i]=m-1;  
    58.     root[n+1]=++cnt;t[n+1]=n;  
    59.     for(int i=1;i<=q;i++)  
    60.     {  
    61.         int a,b;ll tmp;  
    62.           
    63.         scanf("%d%d",&a,&b);  
    64.         if(b<m)  
    65.         {  
    66.             now=a,w=b;  
    67.             query(root[now],1,m-1+q);//找到出队的点   
    68.             printf("%lld ",out);  
    69.             tmp=out,now=n+1;w=a;  
    70.             query(root[now],1,n+q); //从最后一列中找x行的最后一个点   
    71.             now=a,pos[now]++,w=m-1+pos[now];  
    72.             update(root[now],1,m-1+q);//把它归入第x棵线段树管理范畴  
    73.             now=n+1,pos[now]++,w=n+pos[now],out=tmp;  
    74.             update(root[now],1,n+q);//把最后一列最后一个点更新为出队的点   
    75.         }  
    76.         else  
    77.         {  
    78.             now=n+1,w=a;  
    79.             query(root[now],1,n+q);//本来就在最后一列,省去维护x行最后一列的操作   
    80.             printf("%lld ",out);  
    81.             pos[now]++,w=n+pos[now];  
    82.             update(root[now],1,n+q);  
    83.         }  
    84.     }  
    85.     return 0;  
    86. }  
  • 相关阅读:
    了解自我
    IT技能栈
    客户端的工作不仅仅只是看起来那么简单
    .NET 基础 一步步 一幕幕[XML基础操作]
    .NET 基础 一步步 一幕幕[Winform应用程序]
    .NET 基础 一步步 一幕幕[面向对象之堆、栈、引用类型、值类型]
    .NET 基础 一步步 一幕幕[面向对象之new、this关键字]
    .NET 基础 一步步 一幕幕[面向对象之静态、非静态]
    .NET 基础 一步步 一幕幕[面向对象之方法、方法的重载、方法的重写、方法的递归]
    .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9828518.html
Copyright © 2011-2022 走看看