權值線段樹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);//在右子樹中,記得減去左子樹個數
}

 

四.例題

黑匣子https://www.luogu.org/problemnew/show/P1801  

仔細模擬即可。

直接上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;
}

 蒟蒻第一次寫博客,請大佬們多多提建議

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM