zoukankan      html  css  js  c++  java
  • Codefroces 374 B Inna and Sequence (树状数组 || 线段树)

    Inna and Sequence

    题意:先给你一个n,一个m, 然后接下来输入m个数,表示每次拳击会掉出数的位置,然后输入n个数,每次输入1或0在数列的末尾加上1或0,如果输入-1,相应m序列的数的位置就会掉出来并且后面的数会向前补位(每次删除操作可以看作是同时进行的,只有删除结束之后才会进行补位),最后输出这个数列的剩下结果,如果数列为空就输出“Poor stack!”。

    题解:一开始想到的思路还是和上次CF889F想到的一样,在删除的位置标记一下,然后每次2分去查找在前面删除操作之后现在需要删除的位置对应哪里,然后再进行相应的位置,注意的就是,要么从后往前删除,且用二分去查找开始的第一个点,因为m序列如果太大的话,每次删除都会有很多时间浪费在不能删除的位置上; 要么就是先把每次对应的全部位置找出来,再进行删除,因为每次删除都会对后面的删除产生影响。

     1 #include<cstdio>
     2 using namespace std;
     3 const int N = 1e6+10;
     4 int n, m, R;
     5 int tree[N], a[N];
     6 int ans[N];
     7 int lowbit(int x)
     8 {
     9     return x&(-x);
    10 }
    11 void Add(int x)
    12 {
    13     while(x <= n)
    14     {
    15         tree[x]++;
    16         x += lowbit(x);
    17     }
    18 }
    19 int Query(int x)
    20 {
    21     int ret = 0;
    22     while(x > 0)
    23     {
    24         ret += tree[x];
    25         x -= lowbit(x);
    26     }
    27     return ret;
    28 }
    29 int Find_pos(int pos)//找到以前删除之后的补位之后的对应位置
    30 {
    31     int l = pos, r = R;
    32     while(l <= r)
    33     {
    34         int mid = l+r >> 1;
    35         int num = Query(mid);
    36         if(mid == num + pos && ans[mid] != -1)
    37         {
    38             return mid;
    39         }
    40         else if(mid < num+ pos) l = mid+1;
    41         else r = mid - 1;
    42     }
    43 }
    44 void Delete()
    45 {
    46     int l = 1, r = m;
    47     int len = R - Query(R);
    48     while(l <= r)//2分寻找每次开始删除的位置,倒着删除
    49     {
    50         int mid = l + r >> 1;
    51         if(len >= a[mid]) l = mid+1;
    52         else r = mid-1;
    53     }
    54     for(int i = l-1; i > 0; i--)
    55     {
    56         int pos = Find_pos(a[i]);
    57         ans[pos] = -1;
    58         Add(pos);
    59     }
    60 }
    61 int main()
    62 {
    63     scanf("%d%d",&n,&m);
    64     for(int i = 1; i <= m; i++)
    65         scanf("%d",&a[i]);
    66     R = 0;
    67     int t;
    68     for(int i = 1; i <= n; i++)
    69     {
    70         scanf("%d",&t);
    71         if(t == -1)
    72             Delete();
    73         else ans[++R] = t;
    74     }
    75     if(R - Query(R) == 0) printf("Poor stack!
    ");
    76     else
    77     {
    78         for(int i = 1; i <= R; i++)
    79         {
    80             if(ans[i]  == -1) continue;
    81             printf("%d",ans[i]);
    82         }
    83     }
    84     return 0;
    85 }

    然后上面那个思路竟然被队长说TLE, 然后最后修改了n发,最终走到了和下面这个版本耗时差不多的慢几十ms的线段树版本操作。

    开一棵线段树保存有效长度,然后每次通过有效长度去删除就好了。同时可以将m序列转化成有效长度,将删除数组的每一位减去前面的个数,就可以从头开始进行删除操作,

    因为你每删除一次数据,有效长度就会减一,所以如果轮到第m个数,那么对于刚开始删除的序列的有效长度就已经减去m-1了。

     1 #include<cstdio>
     2 #define lson l,m,rt<<1
     3 #define rson m+1,r,rt<<1|1
     4 using namespace std;
     5 const int N = 1e6+10;
     6 int n, m;
     7 int tree[N<<2], ans[N], Delt[N];
     8 void Add(int L,int C,int l, int r, int rt)
     9 {
    10     tree[rt]++;
    11     if(l == r)
    12     {
    13         ans[l]  = C;
    14         return ;
    15     }
    16     int m = l+r >> 1;
    17     if(L <= m) Add(L,C,lson);
    18     else Add(L,C,rson);
    19 }
    20 void Delete(int Num, int l, int r, int rt)
    21 {
    22     tree[rt]--;
    23     if(l == r)
    24     {
    25         ans[l] = -1;
    26         return ;
    27     }
    28     int m = l+r >> 1;
    29     if(tree[rt<<1] >= Num) Delete(Num, lson);
    30     else Delete(Num-tree[rt<<1],rson);
    31 }
    32 int main()
    33 {
    34     //ios::sync_with_stdio(false);
    35     //cin.tie(0);
    36     //cout.tie(0);
    37     scanf("%d%d",&n,&m);
    38     for(int i = 0; i < m; i++)
    39     {
    40         scanf("%d",&Delt[i]);
    41         Delt[i] -= i;//将位置转化成长度
    42     }
    43     int tot = 0;
    44     int tmp;
    45     for(int i = 1; i <= n; i++)
    46     {
    47         scanf("%d",&tmp);
    48         if(tmp != -1)
    49             Add(++tot,tmp,1,n,1);
    50         else
    51         {
    52             for(int i = 0; i < m; i++)
    53             {
    54                 if(tree[1] < Delt[i]) break;
    55                 else Delete(Delt[i],1,n,1);
    56             }
    57         }
    58     }
    59     if(tree[1] == 0) printf("Poor stack!
    ");
    60     else
    61     {
    62         for(int i = 1; i <= tot; i++)
    63             if(ans[i] != -1)
    64                 printf("%d",ans[i]);
    65     }
    66     return 0;
    67 }
  • 相关阅读:
    Java Web Start应用管理
    搭建java开发环境需要什么软件,怎么搭建java开发环境?
    制作WinPE
    今天看见.do网页,疑惑,这是什么文件??又是什么新技术??查了一下
    VC用ADO访问数据库全攻略
    ASP连接11种数据库语法总结
    asp.net里导出excel表方法汇总
    ASP.NET 发邮件方法
    ASP.NET 网站开发日常异常总汇(持续更新)
    javascript操作JSON
  • 原文地址:https://www.cnblogs.com/MingSD/p/8424377.html
Copyright © 2011-2022 走看看