Luo Gu P1168 median --set / segment tree

The first wave of links  https://www.luogu.com.cn/problem/P1168

This question we have two written

The first segment tree it is, we first need the original discrete data, segment tree information is maintained within the range of the number of how many,

Each addition of two numbers (that is, single-point modification), when a query is to find the median ((x + 1) / 2) the location of

Analyzing each come to a point in the left sub-tree of a digital number (y) is not greater than or equal to the currently find if the number k continue to go left subtree

If the number of digits (y) left subtree is less than the current number k are looking for, then it will subtract k y, and then go to the right subtree, go all the way you can find the location where the median

Then the position corresponding to the discrete point before the output corresponding to it such complexity is O (nlogn) of

Paste the code-hand

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int M=1e6+7;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
struct qwq{int w,id;}s[M];
int n,xs[M],xp,fr[M];
struct node{int l,r,sum;}e[M];
void build(int x,int l,int r){
    e[x].l=l; e[x].r=r;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1^1,mid+1,r);
}
void up(int x){e[x].sum=e[x<<1].sum+e[x<<1^1].sum;}
void ins(int x,int k){
    if(e[x].l==e[x].r){
        e[x].sum++;
        return ;
    }
    int mid=(e[x].l+e[x].r)>>1;
    if(k<=mid) ins(x<<1,k);
    else ins(x<<1^1,k);
    up(x);
}
int find(int x,int S){
    if(e[x].l==e[x].r) return e[x].l;
    if(e[x<<1].sum>=S) return find(x<<1,S);
    return find(x<<1^1,S-e[x<<1].sum);
}
int cnt=1;
int main(){
    n=read();
    for(int i=1;i<=n;i++){
        s[i].w=read();
        xs[++xp]=s[i].w;
    }
    sort(xs+1,xs+1+xp);
    for(int i=1;i<=n;i++){
        int now=lower_bound(xs+1,xs+xp+1,s[i].w)-xs;
        s[i].id=now; fr[now]=s[i].w;
    }
//    for(int i=1;i<=n;i++) printf("%d ",s[i].id); puts("");
//    for(int i=1;i<=n;i++) printf("%d ",fr[i]); puts("");
    build(1,1,n);
    ins(1,s[1].id);
    for(int i=1;i<=n;i+=2){
        int ans=find(1,(i+1)/2);
        printf("%d\n",fr[ans]);
        ins(1,s[++cnt].id);
        ins(1,s[++cnt].id);
    }
    return 0;
}
View Code

Another approach is to use multiset maintenance, we will iterator It always points to the median, each insert two numbers

If the two numbers than he, will It ++, because the median after a position where the current It

Similarly, if two numbers than he was small, it will It--, if one large and one small, then the median position unchanged, so that a satisfactory solution to the problem

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<set>
using namespace std;
const int M=1e6+7;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,s[M],ans[M];
multiset<int>S; 
multiset<int>::iterator It; 
int main(){
    //freopen("1.in","r",stdin);
    n=read(); for(int i=1;i<=n;i++) s[i]=read();
    S.insert(s[1]); 
    It=S.lower_bound(s[1]);
    int cnt=1;
    for(int i=1;i<=(n+1)/2;i++){
        ans[i]=*It;
        S.insert(s[++cnt]);
        S.insert(s[++cnt]);
        if(s[cnt]>=*It&&s[cnt-1]>=*It) ++It;
        else if(s[cnt]<*It&&s[cnt-1]<*It) --It;
        printf("%d\n",ans[i]);
    }
    return 0;
}
View Code

 

 

Guess you like

Origin www.cnblogs.com/yourinA/p/12000297.html