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;
    }
    

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

  • 相关阅读:
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    Python for Data Science
    软件工程实践总结
  • 原文地址:https://www.cnblogs.com/zmyzmy/p/9529234.html
Copyright © 2011-2022 走看看