https://www.patest.cn/contests/gplt/L3-002
题意:普通的入栈出栈操作和PeekMedian。PeekMedian的作用是求当前栈中第几小的数。
思路:没做过主席树,好像第一次用线段树求区间第k大,query那里卡了好半天,看了别人的。。
线段树中每个节点的值代表在这个区间内有多少个元素。
tree的val值刚开始被赋予0,代表没有这个数。入栈更新加一,出栈更新减一。
重点就是查询那里,若左儿子代表元素个数大于元素查询个数,则递归左子树。否则元素查询个数减去左子树元素个数,递归右子树。
还是对线段树理解不深啊,前些日子刚复习了一会就干开了别的,任重道远啊。。
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stack>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 100005;
const int INF = 0x3f3f3f3f;
struct line
{
int l, r;
int val;
}tree[4*N];
void build(int i, int l, int r)
{
tree[i].l = l;
tree[i].r = r;
tree[i].val = 0;
if(tree[i].l==tree[i].r) return;//记得返回啊。。草
int mid = (tree[i].l+tree[i].r)>>1;
build(i*2, l, mid);
build(i*2+1, mid+1, r);
}
void update(int i, int l, int r, int pos, int value)
{
if(tree[i].l==tree[i].r && tree[i].l==pos)
{
tree[i].val+=value;
return;
}
int mid = (tree[i].l+tree[i].r)>>1;
if(mid >= pos) update(i*2, l, mid, pos, value);
else update(i*2+1, mid+1, r, pos, value);
tree[i].val = tree[i*2].val+tree[i*2+1].val;
}
int query(int i, int l, int r, int pos)
{
if(tree[i].l==tree[i].r)
{
return tree[i].l;
}
int mid = (tree[i].l+tree[i].r)>>1;
if(tree[i*2].val>=pos) query(i*2, l, mid, pos);
else query(i*2+1, mid+1, r, pos-tree[i*2].val);
}
int main()
{
// freopen("in.txt", "r", stdin);
int n, num;
char s[N];
stack<int>sta;
scanf("%d", &n);
build(1, 0, N);
while(!sta.empty()) sta.pop();
while(n--)
{
scanf("%s", s);
if(!strcmp(s, "Push"))
{
scanf("%d", &num);
sta.push(num);
update(1, 0, N, num, 1);
}
else if(!strcmp(s, "Pop"))
{
if(sta.empty())
{
printf("Invalid\n");
continue;
}
num = sta.top();
sta.pop();
printf("%d\n", num);
update(1, 0, N, num, -1);
}
else if(!strcmp(s, "PeekMedian"))
{
if(sta.empty())
{
printf("Invalid\n");
continue;
}
int len = sta.size();
if(len%2==0) len/=2;
else len = (len+1)/2;
num = query(1, 0, N, len);
printf("%d\n", num);
}
}
return 0;
}