luogu P1168 中位数

窒息

这道题令我头秃

问了问学长思路

学长如是说:

“这道题有很多种解题方法,但是你想用线段树对吧

可以用平衡树来解决,但是你不会,还有主席树,你也不会,

我又想到了一种需要离散化的线段树做法……”

所以说那么多我不会的干什么啊!

这道题我看了很多题解都没看懂

大概是因为用线段树做有一个数组num记录的是什么没有理解

那思路嘛

求中位数

首先开一个线段树,每当出现一个数时,便把那个数所在的数组加一,表示出现次数

当你找中位数的时候,从根开始,分别看左子树和右子树的区间和

如果要找的中位数的位置,即编号x,小于左子树的区间和l

那么该中位数就在左子树中

反之,则在右子树的x - l位置上

emmmm哇还是画图比较好

然而我没有画图软件所以请自己画一画体验一下

看一下代码吧

#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 100010

struct TREE {
    int l,r,num;
} tree[maxn << 2];//开四倍啊我一开始忘了wa了两个点

int a[maxn],b[maxn];//a是原数组,b是排序去重后的

void build(int l,int r,int now) {
    tree[now].l = l;
    tree[now].r = r;
    int mid = (l + r) >> 1;
    if(l == r)
        return ;
    build(l,mid,now << 1);
    build(mid + 1,r,now << 1 | 1);
}//建树的处理

void update(int now,int k) {//当一个位置上有数的时候更新一下,num++
    ++tree[now].num;
    if(tree[now].l == tree[now].r)
        return ;
    int mid = (tree[now].l + tree[now].r) >> 1;
    if(k <= mid)
        update(now << 1,k);
    else
        update(now << 1 | 1,k);
}

int query(int now,int x) {
    if(tree[now].l == tree[now].r)
        return tree[now].l;
    if(x <= tree[now << 1].num)//如果小于左子树区间和,则中位数在左子树中
        return query(now << 1,x);
    else//反之在右子树里,这是x在右子树中的位置是x - num
        return query(now << 1 | 1,x - tree[now << 1].num);
}

int main() {
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) {
        scanf("%d",&a[i]);
        b[i] = a[i];
    }
    sort(b + 1,b + n + 1);
    int k = unique(b + 1,b + n + 1) - b;//将b排序去重
    build(1,n,1);
//    for(int i = 1;i < k;i++)
//    printf("qwq %d ",b[i]);
//    printf("\n");
    for(int i = 1; i <= n; i++) {
        int www = lower_bound(b + 1,b + k + 1,a[i]) - b;//求出每次插入的数的位置
    //    printf("qwq %d   %d qwq\n",a[i],www);
        update(1,www);
        if(i % 2)
            printf("%d\n",b[query(1,i / 2 + 1)]);//输出中位数所在位置上的数
    }
    return 0;
}

大概还比较详细吧www

最后说一下,ljq学长穿了一件帅气的新衬衫哈哈哈哈哈wxsl

————————————————————几分钟的分割线————————————————————————

阿对

还有一种短一点的写法

#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 100010

struct QAQ {
    int data,num;
} a[maxn];

int sum[maxn * 4],rank[maxn];

int cmp(QAQ x,QAQ y){
    return x.data < y.data;
}

void insert(int now,int l,int r,int x) {
    sum[now]++;
    if(l == r)
        return ;
    int mid = (l + r) >> 1;
    if(x <= mid)
        insert(now * 2,l,mid,x);
    else
        insert(now * 2 + 1,mid + 1,r,x);
}

int query(int now,int l,int r,int k) {
    if(l == r)
        return l;
    int mid = (l + r) >> 1;
    if(sum[now * 2] >= k)
        return query(now * 2,l,mid,k);
    else
        return query(now * 2 + 1,mid + 1,r,k - sum[now * 2]);
}

int main() {
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n; i++) {
        scanf("%d",&a[i].data);
        a[i].num = i;
    }
    sort(a + 1,a + n + 1,cmp);
    for(int i = 1; i <= n; i++)
        rank[a[i].num] = I;//这里的离散化就不太一样反正懂就好了www
    for(int i = 1; i <= n; i++) {
        insert(1,1,n,rank[i]);
        if(i % 2)
            printf("%d\n",a[query(1,1,n,i / 2 + 1)].data);
    }
    return 0;
}
//道理都一样就是没有提前建树短一些23333

 

posted @ 2019-01-20 20:23  ./seven  阅读(272)  评论(0编辑  收藏  举报