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
对于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
#include
#include
#include
#include
#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->xs[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
#include
#include
#include
#include
#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]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
#include
#include
#include
#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 (x1;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->Rreturn;
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;
}