zoukankan      html  css  js  c++  java
  • 权值线段树1

    一.权值线段树与线段树的区别:

    • 权值线段树维护数的个数,数组下标代表整个值域(如果值域太大,可以离散化,后面会有介绍)

    • 线段树则是直接维护每个数

    二.权值线段树的用处

    1.寻找第K大(整个区间,即左边界为1,右边界为n)

    2.逆序对(呵呵归并也能求)

    3.最大差&最小差(??!)

    4..............

    三.权值线段树的具体实现

    没什么好说的,直接上代码(丑):

    建树(build):

    inline void build(int root,int L,int R)
    {
        tree[root].l=L;
        tree[root].r=R;
        if(L==R)
        {
            //初始化
            return;
       	}  
        int mid=(L+R)>>1;
        build(root<<1,L,mid);//建左儿子
        build(root<<1|1,mid+1,R);//建右儿子
    }
    

    更新(update):

    inline void update(int root,int t)
    {
        if(tree[root].l==tree[root].r)
        {
            //更新数据     
            return;
        }
        int mid=(tree[root].l+tree[root].r)>>1;
        if(t<=mid) update(root<<1,t);//在左儿子中
        else update(root<<1|1,t);//在右儿子中
        //维护一下(push_up)
    }
    

    这两个部分与普通线段树没什么两样啊----------

    询问整体第k大(query):

    在线段树上进行二分:

    先看左子树数的个数,设其个数为f.

    如果f>=t递归进入左子树寻找

    如果f<k递归进入右子树寻找第f-k大

    整体二分

    //询问整个区间第t大(这里t代表k)//tree[root].s代表tree[root].l至tree[root].r值域中数的个数总和
    inline int query(int root,int t)
    {
        if(tree[root].l==tree[root].r)
            return tree[root].l;//由于数组下标维护的是值域,直接返回其下标
        if(t<=tree[root<<1].s) return query(root<<1,t);//在左子树中
        else return query(root<<1|1,t-tree[root<<1].s);//在右子树中,记得减去左子树个数
    }
    

    四.例题

    黑匣子

    仔细模拟即可。

    直接上AC代码:

    #include<bits/stdc++.h>
    #define N 200005
    using namespace std;
    int m,n,k;
    int a[N],b[N],u[N];
    struct MM{
        int l,r,s;
    }tree[N<<2];
    inline void build(int root,int L,int R)
    {
        tree[root].l=L;
        tree[root].r=R;
        if(L==R) return;
        int mid=(L+R)>>1;
        build(root<<1,L,mid);
        build(root<<1|1,mid+1,R);
    }
    inline void update(int root,int t)
    {
        if(tree[root].l==tree[root].r)
        {
            tree[root].s++;//个数加一
            return;
        }
        int mid=(tree[root].l+tree[root].r)>>1;
        if(t<=mid) update(root<<1,t);
        else update(root<<1|1,t);
        tree[root].s=tree[root<<1].s+tree[root<<1|1].s;
    }
    inline int query(int root,int t)
    {
        if(tree[root].l==tree[root].r)
            return tree[root].l;
        if(t<=tree[root<<1].s) return query(root<<1,t);
        else return query(root<<1|1,t-tree[root<<1].s);
    }
    int main()
    {
        cin>>m>>n;
        for(int i=1;i<=m;i++)
        {
            cin>>a[i];
            b[i]=a[i];
        }
        for(int i=1;i<=n;i++)
            cin>>u[i];
        sort(b+1,b+m+1);
        int s=unique(b+1,b+m+1)-(b+1);//离散化(若值域很大),s是数组b中不重复的数的个数
        build(1,1,s);//依s建树
        int h=0;
        while(n!=h)
        {
            h++;
            for(int i=u[h-1]+1;i<=u[h];i++)
            {
                int v=lower_bound(b+1,b+s+1,a[i])-b;//v是a[i]在数组b中所处的位置(注意之前数组b排了序)
                update(1,v);
            }
            cout<<b[query(1,++k)]<<endl;
        }
        return 0;
    }
    

    蒟蒻第一次写博客,请大佬们多多提建议

  • 相关阅读:
    增量更新代码步骤记录
    软件缺陷管理基本流程
    数据库语言(三):MySQL、PostgreSQL、JDBC
    eclipse的使用
    数据库语言(二):SQL语法实例整理
    windows下MySql没有setup.exe时的安装方法
    数学:完全独立于实际场景的情况下定义的概念,可以正确的描述世界
    数学语言和程序语言的对比:面向过程与面向集合&命题
    iOS开发之IMP和SEL(方法和类的反射)
    iOS之UIButton的normal和selected状态切换
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/9529234.html
Copyright © 2011-2022 走看看