洛谷p1168[线段树+离散化]

https://www.luogu.org/problemnew/show/P1168

离散化:有些数据本身很大, 自身无法作为数组的下标保存对应的属性。如果这时只是需要这堆数据的相对属性, 那么可以对其进行离散化处理。当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。
参考:https://blog.csdn.net/qq_40046426/article/details/82760696
https://blog.csdn.net/qq_40774175/article/details/80343164

离散化模板

 for(int i=1; i<=n; i++)
    {
        cin>>a[i];
        b[i] = a[i];
    }
    sort(b+1,b+1+n);
    int len = unique(b+1,b+1+n)-(b+1);   //len就是去重之后的数组长度,unique用法可以去网上看看,用法简单
    for(int i=1; i<=n; i++)
    {
          a[i] = lower_bound(b+1,b+1+len,a[i])-b;   //a[i]就是直接离散化出来的数组

    }

补充:lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

const int maxn=1e5+10;
int n,m;
int a[maxn],b[maxn];
struct node
{
    int l,r,mid;
    int num;//表示出现次数
} t[maxn<<2];//树节点
void build(int l,int r,int k)
{
    t[k].l=l,t[k].r=r,t[k].mid=(l+r)>>1;
    if(l==r)
        return;
    build(l,t[k].mid,k<<1);
    build(t[k].mid+1,r,k<<1|1);
}
void update(int k,int pos)
{
    ++t[k].num;
    if(t[k].l==t[k].r)
        return;
    if(pos<=t[k].mid)
        update(k<<1,pos);
    else
        update(k<<1|1,pos);
}
int query(int k,int num)
{
    if(t[k].l==t[k].r)
        return t[k].l;//返回数组下标
    if(num<=t[k<<1].num)
        return query(k<<1,num);
    else
        return query(k<<1|1,num-t[k<<1].num);
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
    }
    sort(b+1,b+1+n);//先排序
    int tot=unique(b+1,b+1+n)-(b+1);//再去重,并且tot为去重后的数组长度
    build(1,n,1);//相当于拿下标建树
    for(int i=1; i<=n; ++i)
    {
        int pos=lower_bound(b+1,b+1+tot,a[i])-b;//a[i]在b数组中出现的位置
        update(1,pos);
        if(i%2)//i/2+1为此时的中位数应该出现的次数
            printf("%d\n",b[query(1,i/2+1)]);
    }
} 

你可能感兴趣的:(大一学习&&acm有关)