美文网首页PAT
B1057 Stack(分块,树状数组+二分)

B1057 Stack(分块,树状数组+二分)

作者: Tsukinousag | 来源:发表于2020-01-23 23:56 被阅读0次

B1057 Stack (30分)

数据范围N ≤10^5​​ ,模拟栈的push和pop的每个过程,求每个过程中栈内元素的中位数。
对于N次查询,使用快排去求中位数O( N * log2(N) ) * O(N)肯定会超时。

//树状数组不是顶级的考纲吗/(ㄒoㄒ)/~~

1.分块

单次查询中位数时间O(N^1/2)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=100005;
const int INF=0x3f3f3f3f;
const int mod=1000000007;
const int sqr=316;//sqrt(100001)向下取整,每块的最大容量。
stack<int>st;
int table[MAX];//hsah
int blocks[sqr];//每个块的当前元素数量
void peekmedian(int k)
{
    int sum=0;
    int idx=0;
    while(sum+blocks[idx]<k)
    {
        sum+=blocks[idx++];
    }
    int num=idx*316;//idx第一个数
    while(sum+table[num]<k)
    {
        sum+=table[num++];
    }
    printf("%d\n",num);
}
void push(int x)
{
      st.push(x);
      blocks[x/sqr]++;
      table[x]++;
}
void pop()
{
    int top=st.top();
    st.pop();
    blocks[top/sqr]--;
    table[top]--;
    printf("%d\n",top);
}
int main()
{
    int n;
    string s,a;
    memset(table,0,sizeof(table));
    memset(blocks,0,sizeof(blocks));
    scanf("%d",&n);
    getchar();
    for(int i=0;i<n;i++)
    {
        cin>>s;
        if(s=="Push")
        {
            int num;
            scanf("%d",&num);
            push(num);
        }
        else if(s=="Pop")
        {
          if(!st.empty())
          {
            pop();
          }
          else
            printf("Invalid\n");
        }
        else if(s=="PeekMedian")
        {
          if(!st.empty())
          {
            int k=st.size();
            int mid;
            if(k%2==1)
                mid=(k+1)/2;
            else
                mid=k/2;
            peekmedian(mid);
          }
          else
            printf("Invalid\n");
        }
    }

    return 0;
}

2.树状数组+二分

对一个序列,用hash记录每个元素出现的个数,那么序列第k大就是求最小的i使得sum(hash[1]~hash(i))>=k成立,用树状数组来解决hash数组求和问题,
等价于求第一个满足getsum(i)>=k的最小i
树状数组求和时间复杂度O(logn),二分查询i时间复杂度O(logn)
总时间O(logn)*O(logn)

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=100005;
const int INF=0x3f3f3f3f;
const int mod=1000000007;
const int sqr=316;//sqrt(100001)向下取整,每块的最大容量。
#define lowbit(i)((i)&(-i))
stack<int>st;
int c[MAX];//树状数组
void update(int x,int v)
{
    for(int i=x;i<=MAX;i+=lowbit(i))
    {
        c[i]+=v;
    }
}
int getsum(int x)
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
    {
        sum+=c[i];
    }
    return sum;
}
int peekmedian(int k)
{
    int l=1,r=MAX,mid;
    while(l<r)
    {
        mid=(l+r)/2;
        if(getsum(mid)>=k)
        {
            r=mid;
        }
        else
            l=mid+1;
    }
    return l;

}
void push(int x)
{
    st.push(x);
    update(x,1);
}
void pop()
{
    int top=st.top();
    st.pop();
    printf("%d\n",top);
    update(top,-1);
}
int main()
{
    int n;
    string s,a;
    memset(c,0,sizeof(c));
    scanf("%d",&n);
    getchar();
    for(int i=0;i<n;i++)
    {
        cin>>s;
        if(s=="Push")
        {
            int num;
            scanf("%d",&num);
            push(num);
        }
        else if(s=="Pop")
        {
          if(!st.empty())
          {
            pop();
          }
          else
            printf("Invalid\n");
        }
        else if(s=="PeekMedian")
        {
          if(!st.empty())
          {
            int k=st.size();
            int mid;
            if(k%2==1)
                mid=(k+1)/2;
            else
                mid=k/2;
            printf("%d\n",peekmedian(mid));
          }
          else
            printf("Invalid\n");
        }
    }

    return 0;
}

相关文章

  • B1057 Stack(分块,树状数组+二分)

    B1057 Stack (30分) 数据范围N ≤10^5​​ ,模拟栈的push和pop的每个过程,求每个过程中...

  • 17-12-8版子

    高精度加法 高精度乘法 快速乘法 二分匹配 阶乘长度(Stirling公式) 并查集 树状数组 树状数组的逆序数 ...

  • 数据结构(二)

    树状数组 POJ 1990: MooFest关于x坐标建立树状数组。先按照v值升序排序,逐个添加到树状数组里。每次...

  • 三种一维树状数组

    单点修改+区间查询 最基本的树状数组 树状数组入门 模板(洛谷P3374 【模板】树状数组1) 区间修改+单点查询...

  • 树状结构转一维数组

    树状结构转数组方法 声明树状对象

  • 树状数组

    复习一下树状数组 树状数组 一种用于处理单点修改和区间查询的数据结构。树状数组C的定义: C[x] = Sum ...

  • 树状数组模板复习

    树状数组模板复习

  • 树状数组求逆序对原理

    归并排序和树状数组都可以用nlogn的算法做到求出逆序对.但这里着重讲树状数组的原理与求法.树状数组最常用的方面就...

  • 「树状数组」

    题目传送门 poj1990题意: 农夫的N (N∈[1, 20,000])头牛参加了"MooFest"之后有了不...

  • 树状数组

    参见: https://www.cnblogs.com/hsd-/p/6139376.htmlhttps://bl...

网友评论

    本文标题:B1057 Stack(分块,树状数组+二分)

    本文链接:https://www.haomeiwen.com/subject/pomnzctx.html