题解:中位数
首先考虑的是二叉搜索树,每次查找当前排名(i+1)/2的数。但是对于某些数据,其递归层数过多,会导致爆栈。
那么显然可以用Treap或Splay。
这里考虑线段树:
由于线段树是一种平衡树,所以一定保证能跑出来。
对于线段树,我们基于二叉搜索树的查找方法并介于线段树平衡的性质求解。
对于线段树的每一个节点,我们记其大小为num,并记录其左边最大值和右边最小值。
在插入时我们考虑存入一个有序数列,保证其根节点的元素单调递增。
则其左边最大值和右边最小值分别为左儿子右端点和右儿子左端点。
在插入时,若:
当前值x=左最大=右最小,显然x=根节点。
我们令根节点的num+1.
当前值x>左最大,往右放;反之,往左放。
在查询时:
就相当于结合了二叉搜索树的找排名,和线段树的单点修改的样子。
#include<iostream> #include<cstdio> #include<algorithm> #define lson l,mid,rn<<1 #define rson mid+1,r,rn<<1|1 using namespace std; int n,a[100010],b[100010],size; struct cym{ int num; int l_size,r_size; }tree[400010]; void update(int rn) { tree[rn].num=tree[rn<<1].num+tree[rn<<1|1].num; tree[rn].l_size=tree[rn<<1].l_size;tree[rn].r_size=tree[rn<<1|1].r_size; } void build(int l,int r,int rn) { if(l==r) { tree[rn].l_size=tree[rn].r_size=b[l]; return; } int mid=(l+r)>>1; build(lson); build(rson); update(rn); } void add(int x,int now) { if(tree[now].l_size==tree[now].r_size&&tree[now].l_size==x) { tree[now].num++; return; } if(x>tree[now<<1].r_size) add(x,now<<1|1); else add(x,now<<1); update(now); } int find(int l,int r,int rn,int rank) { if(l==r) return tree[rn].l_size; int mid=(l+r)>>1; int ans=0; if(rank<=tree[rn<<1].num) ans=find(lson,rank); else ans=find(rson,rank-tree[rn<<1].num); return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+1+n); size=unique(b+1,b+1+n)-(b+1); build(1,size,1); for(int i=1;i<=n;i++) { add(a[i],1); if(i&1) printf("%d\n",find(1,size,1,(i+1)>>1)); } }