PAT甲级1057 Stack【树状数组】【二分】

题目https://pintia.cn/problem-sets/994805342720868352/problems/994805417945710592

题意:对一个栈进行push, pop和找中位数三种操作。

思路:

好久没写题。感觉傻逼题写多了稍微有点数据结构的都不会写了。

pop和push操作就不说了。

找中位数的话就二分去找某一个数前面一共有多少小于他的数,找到那个小于他的数刚好等于一半的。

找的过程中要用到前缀和,所以自然而然就应该上树状数组。

要注意树状数组的界应该是1e5而不是当前数的最大值。

 1 //#include<bits/stdc++>
 2 #include<stdio.h>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<stdlib.h>
 7 #include<queue>
 8 #include<map>
 9 #include<stack>
10 #include<set>
11
12 #define LL long long
13 #define ull unsigned long long
14 #define inf 0x7f7f7f7f
15
16 using namespace std;
17 const int maxn = 1e5 + 5;
18 int n, size;
19 int sum[maxn];
20 stack<int>sss;
21 int small = 1, big = 1e5;
22
23 void add(int x, int val)
24 {
25     while(x < 1e5){
26         sum[x] += val;
27         x += (x & -x);
28     }
29 }
30
31 int query(int x)
32 {
33     int ans = 0;
34     while(x){
35         ans += sum[x];
36         x -= (x & -x);
37     }
38     return ans;
39 }
40
41 int main()
42 {
43     scanf("%d", &n);
44
45     while(n--){
46         string op;
47         cin>>op;
48         if(op == "Push"){
49             int key;
50             cin>>key;
51             sss.push(key);
52             //small = min(small, key);
53             //big = max(big, key);
54             add(key, 1);
55         }
56         else if(op == "Pop"){
57             if(sss.size() == 0){
58                 printf("Invalid\n");
59             }
60             else{
61                 add(sss.top(), -1);
62                 printf("%d\n", sss.top());
63                 sss.pop();
64             }
65         }
66         else if(op == "PeekMedian"){
67             if(sss.size() == 0){
68                 printf("Invalid\n");
69             }
70             else{
71                 int st = small, ed = big;
72                 int ans = 0;
73                 while(st <= ed){
74                     int mid = (st + ed) / 2;
75                     size = sss.size();
76                     int res = query(mid);
77                     if(res < (size + 1) / 2){
78                         st = mid + 1;
79                     }
80                     else{
81                         ans = mid;
82                         ed = mid - 1;
83                     }
84                 }
85                 printf("%d\n", ans);
86             }
87         }
88     }
89
90     return 0;
91 } 

原文地址:https://www.cnblogs.com/wyboooo/p/10582667.html

时间: 2024-11-08 02:16:12

PAT甲级1057 Stack【树状数组】【二分】的相关文章

POJ 2892 Tunnel Warfare (树状数组+二分)

题目大意: 三个操作 D pos  将pos位置摧毁,让它和周围不相连. Q pos 问和pos 相连的有多少个村庄. R 修复最近摧毁的村庄. 思路分析: 树状数组记录这个区间有多少个1. 如果  [s-e] 有e-s+1个1 的话.那么这个区间是相连的. 这样的话,我们就可以用二分的办法求出与某个位置最大相连的数量. 还有这里二分 while(l<=r) { if(满足) { ans=mid; l=mid+1; } else r=mid-1; } #include <cstdio>

HDU 2852 KiKi&#39;s K-Number【 树状数组 二分 】

题意:给出m个操作,0:是增加一个数,add(x,1)1:是删除一个指定的数,这个是看sum(x) - sum(x-1)是否为0,为0的话则不存在,不为0的话,则add(x,-1)2:是查询比x大的数中第k大的数,先求出比x小的个数s,假设比x大的数中第k大的数为y,那么比y小的个数有s+k个二分y的值来找 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath&g

HDU2852 KiKi&#39;s K-Number 树状数组+二分

这题就是给了你三种操作, 1:往容器中一个元素 x 2::把容器中的元素x删除 3:查询比 x大的第k个数 想法:添加元素跟删除元素  直接是以数本身为序号然后以 value值为1和-1即可,相当于计数,至于找比x第k个大的数,那就看看当前往后数k个数的第一个数是哪个就可以了,一开始直接找出来,然后往后暴力的扫了一遍,结果错了,没关系,反应很快,直接改了个二分查找,然后就过了,弄清楚如何建立这个树状数组即可 #include<iostream> #include<cstdio> #

HDU 2852 KiKi&#39;s K-Number (树状数组 &amp;&amp; 二分)

题意:给出对容器的总操作次数n, 接下来是这n个操作.这里对于一个容器提供三种操作, 分别是插入.删除和查找.输入0  e表示插入e.输入1  e表示删除e,若元素不存在输出No Elment!.输入2  e  k表示查找比e大且第k大的数, 若不存在则输出Not Find! 分析:这里考虑树状数组做的原因是在第三个操作的时候, 只要我们记录了元素的总数, 那通过求和操作, 便能够高效地知道到底有多少个数比现在求和的这个数要大, 例如 tot - sum(3)就能知道整个集合里面比3大的数到底有

ZOJ 3635 树状数组+二分

这题那时怎么想就是想不出来--而且今晚没有多大状态,自己都晕了--一题没做出来-- baoge解释好久才懂--唉--线段树,树状数组用得还是不够熟啊-- WA了二发,才知道二分错了,二分好久不用,老是出错了现在-- #include<iostream> #include<cstring> #include<string> #include<cstdio> #define sca(a) scanf("%d",&a) #define

HDU 5592 ZYB&#39;s Premutation(树状数组+二分)

题意:给一个排列的每个前缀区间的逆序对数,让还原 原序列. 思路:考虑逆序对的意思,对于k = f[i] - f[i -1],就表示在第i个位置前面有k个比当前位置大的数,那么也就是:除了i后面的数字之外,它是在剩下的数字当中第k+1大的. 知道这个之后,可以用树状数组来帮助找出剩下的数中第k大的数,刚开始我们可以让1-n中每个元素都标记为1,那么他们的前缀和就代表它是第几小.所以,我们可以对于他们的和来二分快速寻找第k大数.其实在树状数组里面是按照第(i-k)小来找的.找完之后要删除这个元素的

POJ 2828 Buy Tickets (线段树 or 树状数组+二分)

题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容易就确定了,那最后第二个人的位置也可以推(与最后一个人的位置无关)...依次就都可以确定所有的人了. 用前缀和的思想,要是这个人的位置确定了,那么就标记这个人位置的值为0,然后回溯更新,跟求逆序对个数的思想比较类似. 线段树: 1 #include <iostream> 2 #include &l

HDU 2852 KiKi&#39;s K-Number(树状数组+二分)

KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2598    Accepted Submission(s): 1199 Problem Description For the k-th number, we all should be very familiar with it. Of course,t

TOJ 4602:高桥和低桥(二分或树状数组+二分)

描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上,所以不算"淹了两次".举例说明:假定高桥和低桥的高度分别是5和2,初始水位为1第一次洪水:水位提高到6(两个桥都被淹),退到2(高桥不再被淹,但低桥仍然被淹)第二次洪水:水位提高到8(高桥又被淹了),退到3.没错,文字游戏.关键在于"又"的含义.如果某次洪水退去之后一座桥仍然被淹(即水位不小于