洛谷-P3871 [TJOI2010]中位数

P3871 [TJOI2010]中位数
题目描述
给定一个由N个元素组成的整数序列,现在有两种操作:

1 add a

在该序列的最后添加一个整数a,组成长度为N + 1的整数序列

2 mid 输出当前序列的中位数

中位数是指将一个序列按照从小到大排序后处在中间位置的数。(若序列长度为偶数,则指处在中间位置的两个数中较小的那个)

例1:1 2 13 14 15 16 中位数为13

例2:1 3 5 7 10 11 17 中位数为7

例3:1 1 1 2 3 中位数为1

输入格式:
第一行为初始序列长度N。第二行为N个整数,表示整数序列,数字之间用空格分隔。第三行为操作数M,即要进行M次操作。下面为M行,每行输入格式如题意所述。

输出格式:
对于每个mid操作输出中位数的值

输入样例
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid
输出样例
5
13
说明
对于30%的数据,1 ≤ N ≤ 10,000,0 ≤ M ≤ 1,000

扫描二维码关注公众号,回复: 915098 查看本文章

对于100%的数据,1 ≤ N ≤ 100,000,0 ≤ M ≤ 10,000

序列中整数的绝对值不超过1,000,000,000,序列中的数可能有重复

每个测试点时限1秒

题解
Treap水过

(这段里的n表示当期序列元素个数)两个堆,一个大根一个小根,分别维护前 (n/2 向上取整)小的元素和后 (n/2 向下取整)小的元素,第奇数次插入大根堆,偶数次插入小根堆。如果小根堆堆顶<大根堆堆顶,说明小根堆内并非后 n/2 小的元素,那么交换堆顶。

线段树。离散后可以用线段树求第k大的元素(k就是中位数的下标)

其余全部详见代码。

代码
Treap

#include<ctime>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gtc() getchar()
using namespace std;
int n,m,tot;
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gtc();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gtc();
    return ret*f;
}
int rd(){return rand()<<16|rand()<<1|(rand()&1);}
struct nod{
    nod* s[2];
    int sum,x,r,siz;
    nod(int xx){s[0]=s[1]=NULL;sum=siz=1;x=xx;r=rd();}
    void puup(){siz=sum+(s[0]!=NULL?s[0]->siz:0)+(s[1]!=NULL?s[1]->siz:0);}
}*rot=NULL;
void rotate(nod* &a,int d)
{
    nod* b=a->s[d^1];
    if (b==NULL) return;
    a->s[d^1]=b->s[d];
    b->s[d]=a;
    a->puup();
    b->puup();
    a=b;
}
void insert(nod* &a,int x)
{
    if (a==NULL){a=new nod(x);return;}
    a->siz++;
    if (a->x==x) {a->sum++;return;}
    int d=a->x<x;
    insert(a->s[d],x);
    if (a->s[d]->r>a->r) rotate(a,d^1);
}
int query(nod* &a,int k)
{
    int s0=a->s[0]!=NULL?a->s[0]->siz:0;
    if (s0>=k) return query(a->s[0],k);
    if (s0+a->sum>=k) return a->x;
    return query(a->s[1],k-s0-a->sum);
}
int main()
{
    srand((int)(time(NULL)));
    n=read();tot=n+1;
    for (int i=1;i<=n;i++)
    insert(rot,read());
    m=read();
    char c;
    for (int i=1;i<=m;i++)
    {
        c=gtc();while (c!='a'&&c!='m') c=gtc();
        if (c=='a') insert(rot,read()),tot++;
        else printf("%d\n",query(rot,tot>>1));
    }
    return 0;
}

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gtc() getchar()
using namespace std;
const int maxn=2e5+5;
int n,m,tot,h[2][maxn],T[2];
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gtc();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gtc();
    return ret*f;
}
void put(int x,int p)
{
    h[p][++T[p]]=x;tot++;
    if (p) push_heap(h[p]+1,h[p]+1+T[p]);
      else push_heap(h[p]+1,h[p]+1+T[p],greater<int>());
}
int get(int p)
{
    if (p) pop_heap(h[p]+1,h[p]+1+T[p]);
      else pop_heap(h[p]+1,h[p]+1+T[p],greater<int>());
    return h[p][T[p]--];
}
int main()
{
    n=read();tot=1;
    for (int i=1;i<=n;i++) put(read(),tot&1);
    m=read();
    char c;
    for (int i=1,x,y;i<=m;i++)
    {
        c=gtc();while (c!='a'&&c!='m') c=gtc();
        while (h[0][1]<h[1][1])
        {
            x=get(0),y=get(1);
            put(x,1);put(y,0);
        }
        if (c=='a') put(read(),tot&1);
        else printf("%d\n",h[1][1]);
    }
    return 0;
}

线段树
可能是前段时间其它东西写多了,线段树写得像平衡树,将就这看看吧

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gtc() getchar()
using namespace std;
const int maxn=1e5+5;
int n,m,tot,TOT,a[maxn<<1],b[maxn<<1];
struct nod{
    nod *s[2];
    int L,R,w;
}*rot=new nod;
char s[maxn];
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gtc();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gtc();
    return ret*f;
}
int fin(int x)
{
    for (int L=1,R=TOT,mid=L+R>>1;L<=R;mid=L+R>>1)
      if (x<b[mid]) R=mid-1;else
      if (x>b[mid]) L=mid+1;else
      return mid;
}
void build(int L,int R,nod *rot)
{
    rot->L=L;rot->R=R;
    if (L==R) {rot->w=0;return;}
    int mid=L+R>>1;
    rot->s[0]=new nod;build(L,mid,rot->s[0]);
    rot->s[1]=new nod;build(mid+1,R,rot->s[1]);
    rot->w=0;
}
void add(nod *now,int x)
{
    if (now->L>x||now->R<x) return;
    now->w++;
    if (now->L==now->R) return;
    int mid=now->L+now->R>>1;
    add(now->s[0],x);
    add(now->s[1],x);
}
int query(nod *now,int k)
{
    if (now->L==now->R) return b[now->L];
    int Lson=now->s[0]->w;
    if (Lson>=k) return query(now->s[0],k);
    return query(now->s[1],k-Lson);
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    m=read();tot=n;
    for (int i=1;i<=m;i++)
    {
        char c=gtc();while (c!='a'&&c!='m') c=gtc();
        s[i]=c;if (c=='a') a[++tot]=read();
    }
    for (int i=1;i<=tot;i++) b[i]=a[i];
    sort(b+1,b+tot+1);
    build(1,tot,rot);
    TOT=tot;
    for (int i=1;i<=n;i++) add(rot,fin(a[i]));
    tot=n+1;
    for (int i=1;i<=m;i++)
      if (s[i]=='a') add(rot,fin(a[tot++]));
      else printf("%d\n",query(rot,tot>>1));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/80342003