洛谷P1168 中位数 的各种做法

洛谷P1168 中位数

 

#include <bits/stdc++.h>
using namespace std;
int n,t;
int b[100005],f[100005],w[100005];    //树状数组 
struct O{
    int x,i;
}a[100005];
 bool cmp(const O &a,const O &b){
    return a.x<b.x;
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i) scanf("%d",&a[i].x),a[i].i=i;
    sort(a+1,a+n+1,cmp);

    //离散化
    t=0;        //a[i].x : [0,1e9]
    a[0].x=-1;
    for (int i=1;i<=n;++i){
        if (a[i].x!=a[i-1].x) w[++t]=a[i].x;
        b[a[i].i]=t;
    }

    //b[i]   now : [1,n]
    for (int i=1;i<=n;++i){
        for (int j=b[i];j<=n;j+=j&-j) f[j]++;
        if (i&1){    // (i%2!=0)
            int l=1,r=n,mid,x;                // [l,r]
            while (l<r){
                mid=(l+r)/2;
                x=0;
                for (int j=mid;j;j-=j&-j) x+=f[j];
                if (x<=i/2) l=mid+1; else r=mid;
            }
            printf("%d\n",w[l]);
        }
    }
     return 0;
 }
树状数组+二分

 

#include <bits/stdc++.h>
using namespace std;
int n,t;
int b[100005],f[200005],w[100005];    //树状数组
struct O{
    int x,i;
}a[100005];
bool cmp(const O &a,const O &b){
    return a.x<b.x;
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i) scanf("%d",&a[i].x),a[i].i=i;
    sort(a+1,a+n+1,cmp);
    
    //离散化
    t=0;        //a[i].x : [0,1e9]
    a[0].x=-1;
    for (int i=1;i<=n;++i){
        if (a[i].x!=a[i-1].x) w[++t]=a[i].x;
        b[a[i].i]=t;
    }
    
    
    //b[i]   now : [1,n]
    
    
    //!!!!注意 树状数组的上限变成 2^17 
    for (int i=1;i<=n;++i){
        for (int j=b[i];j<=1<<17;j+=j&-j) f[j]++;
        if (i&1){    // (i%2!=0)
            int x=i/2+1,k=0;
            for (int j=1<<17;j;j>>=1) 
            if (x>f[k+j]) x-=f[k+j],k+=j;
            printf("%d\n",w[k+1]);
        }
    }

     return 0;
}
树状数组直接定位

 

#include <bits/stdc++.h>
using namespace std;
int n,t;
int b[100005],w[100005];
struct O{
    int x,i;
}a[100005];
bool cmp(const O &a,const O &b){
    return a.x<b.x;
}

int cnt,rt;
struct node{
    int l,r,s;
}f[200005];
int build(int l,int r){
    int u=++cnt;
    if (l==r) return u;
    f[u].s=0;
    f[u].l=build(l,(l+r)/2);
    f[u].r=build((l+r)/2+1,r);
    return u;
}
void add(int u,int l,int r,int x){
    f[u].s++;
    if (l==r) return;
    if (x<=(l+r)/2) add(f[u].l,l,(l+r)/2,x);
        else add(f[u].r,(l+r)/2+1,r,x);
}
int find(int u,int l,int r,int k){
    if (l==r) return l;
    if (k<=f[f[u].l].s) return find(f[u].l,l,(l+r)/2,k);
        else return find(f[u].r,(l+r)/2+1,r,k-f[f[u].l].s);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i) scanf("%d",&a[i].x),a[i].i=i;
    sort(a+1,a+n+1,cmp);
    
    //离散化
    t=0;        //a[i].x : [0,1e9]
    a[0].x=-1;
    for (int i=1;i<=n;++i){
        if (a[i].x!=a[i-1].x) w[++t]=a[i].x;
        b[a[i].i]=t;
    }
    
    //b[i]   now : [1,n]
    rt=build(1,t);
    for (int i=1;i<=n;++i){
        add(rt,1,t,b[i]);
        if (i&1){
            printf("%d\n",w[find(rt,1,t,i/2+1)]);
        }
    }
     return 0;
}
普通线段树

 

#include <bits/stdc++.h>
using namespace std;
int n,x,rt,t;
struct node{
    int l,r,s;
}a[100005*20];
void add(int &u,int p,int q,int x){
    if (!u) u=++t;
    a[u].s++;
    if (p==q) return;
    if (x<=(p+q)/2) add(a[u].l,p,(p+q)/2,x);
        else add(a[u].r,(p+q)/2+1,q,x);
}
int find(int u,int p,int q,int k){
    if (p==q) return p;
    if (k<=a[a[u].l].s) return find(a[u].l,p,(p+q)/2,k);
        else return find(a[u].r,(p+q)/2+1,q,k-a[a[u].l].s);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d",&x);
        add(rt,0,1e9,x);
        if (i&1){
            printf("%d\n",find(rt,0,1e9,i/2+1));
        }
    }
    return 0;
}
动态开点线段树(不用离散化)

 

#include <bits/stdc++.h>
using namespace std;
int n,x,rt,t;
struct O{
    int l,r,v,s;
}a[3000005];
void up(int u){
    a[u].s=a[a[u].l].s+a[a[u].r].s+1;
}
void splitS(int u,int k,int &l,int &r){    //前k个位l
    if (!k) {l=0; r=u; return;}
    if (k==a[u].s) {l=u; r=0; return;}
    if (k<=a[a[u].l].s) r=u,splitS(a[u].l,k,l,a[u].l);
    else l=u,splitS(a[u].r,k-a[a[u].l].s-1,a[u].r,r);
    up(u);
}
void splitV(int u,int k,int &l,int &r){    //.v<=k的为l 
    if (u==0) {l=r=0; return;}
    if (k<a[u].v) r=u,splitV(a[u].l,k,l,a[u].l);
    else l=u,splitV(a[u].r,k,a[u].r,r);
    up(u);
}
int merge(int l,int r){
    if (!l||!r) return l+r;
    if (1ll*rand()*(a[l].s+a[r].s)<1ll*RAND_MAX*a[l].s){
        a[l].r=merge(a[l].r,r); up(l); return l;
    }else{
        a[r].l=merge(l,a[r].l); up(r); return r;
    }
}
void Add(int x){
    int A,B;
    a[++t].v=x; a[t].s=1;
    splitV(rt,x,A,B);
    rt=merge(merge(A,t),B);
}
int Find(int u,int k){
    if (a[a[u].l].s+1==k) return a[u].v;
    if (k<=a[a[u].l].s) return Find(a[u].l,k);
        else return Find(a[u].r,k-a[a[u].l].s-1);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d",&x);
        Add(x);
        if (i&1){
            printf("%d\n",Find(rt,i/2+1));
        }
    }
    return 0;
}
非旋treap

 

#include <bits/stdc++.h>
using namespace std;
int n,x,rt,t;
int fa[100005],w[100005],ch[100005][2],s[100005];
void up(int x){
    s[x]=s[ch[x][0]]+s[ch[x][1]]+1;
}
void Rotate(int x){        //一次旋转 
    int y=fa[x],i=ch[y][1]==x;
    ch[fa[y]][ch[fa[y]][1]==y]=x;    
    ch[y][i]=ch[x][i^1];
    ch[x][i^1]=y;
    fa[ch[y][i]]=y;
    fa[x]=fa[y];
    fa[y]=x;
    up(y); up(x);
}
void splay(int x){        //把x转到根 
    int y,z;
    while (fa[x]){
        y=fa[x],z=fa[y];
        if (z) (ch[z][0]==y)^(ch[y][0]==x)?Rotate(x):Rotate(y);
        Rotate(x);
    }
}
void ADD(int x){
    if (!rt){
        rt=++t;
        w[t]=x;
        s[t]=1;
        return;
    }
    int u=rt;
    while (ch[u][w[u]<x]) u=ch[u][w[u]<x];
    ch[u][w[u]<x]=++t;
    w[t]=x; fa[t]=u;
    splay(t); rt=t;
}
void Find(int k){        //找到第k个 
    int u=rt;
    while (1){
        if (k==s[ch[u][0]]+1){
            splay(u); rt=u; return;
        }
        if (k<=s[ch[u][0]]) u=ch[u][0];
            else k=k-s[ch[u][0]]-1,u=ch[u][1];
    }
}
int main(){
//    freopen("data4.in","r",stdin);
//    freopen("splay.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d",&x);
        ADD(x);
        if (i&1){
            Find(i/2+1);
            printf("%d\n",w[rt]);
        }
    }
    return 0;
}
普通splay

 

#include <bits/stdc++.h>
using namespace std;
priority_queue <int,vector<int>,less<int> > a;    //大根 
priority_queue <int,vector<int>,greater<int> > b;    //小根 
int n,x;
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;++i){
        scanf("%d",&x);
        if (a.empty()||x<=a.top()) a.push(x); else b.push(x);
        while (a.size()>b.size()+1)    b.push(a.top()),a.pop();
        while (a.size()<b.size())    a.push(b.top()),b.pop();
        if (i&1) printf("%d\n",a.top());
    }
    return 0;
}
堆(最优)

 

posted @ 2021-07-31 11:44  cyz666  阅读(109)  评论(0编辑  收藏  举报