zoukankan      html  css  js  c++  java
  • 不修改的主席(HJT)树-HDU2665,POJ-2104;

    参考:优秀的B站视频;

        和 https://blog.csdn.net/creatorx/article/details/75446472

    感觉主席树这个思路是真的优秀,每次在前一次的线段树的基础上建立一颗新的小线段树;所以更新和查询都是要前后两个根节点进行操作;

    利用引用,只用修改此次的节点,而不动前一次的线段树;

    主席树可用在求区间的第K大的数上:思路是:

    我们也可以利用前缀和这个思想来解决建树这个问题,我们只需要建立n颗“前缀”线段树就行,第i树维护[1,i]序列,这样我们处理任意区间l, r时就可以通过处理区间[1,l - 1], [1,r],就行,然后两者的处理结果进行相加相减就行。为什么满足相加减的性质,我们简单分析一下就很容易得出。如果在区间[1,l - 1]中有x个数小于一个数,在[1,r]中有y个数小于那个数,那么在区间[l,r]中就有y - x 个数小于那个数了,这样就很好理解为什么可以相加减了,另外,每颗树的结构都一样,都是一颗叶节点为n个的线段树。

    这里还有一个利用vector离散化的操作;

    hdu ac的:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <vector>
    using namespace std;
    #define pb push_back 
    const int maxn = 100009;
    
    struct node {
        int l,r;
        int sum;
    }T[maxn*20];
    int a[maxn],root[maxn];
    vector<int>v;
    int getid(int x){
        return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
    }
    int n,m,cnt,x,y,k;
        
    void init(){
        v.clear();
        memset(T,0,sizeof(T));
        cnt = 0;
    }
    void update(int l,int r,int &x,int y,int pos)
    {
        T[++cnt] = T[y]; T[cnt].sum++; x = cnt;
        if(l==r)return;
        int mid = (l+r)>>1;
        if(mid>=pos)
            update(l,mid,T[x].l,T[y].l,pos);
        else update(mid+1,r,T[x].r,T[y].r,pos);
    }
            
    int query(int l,int r,int x,int y,int pos)
    {
        if(l==r)return l;
        int sum = T[T[y].l].sum - T[T[x].l].sum;
        int mid = (l+r)>>1;
        if(sum >= pos)
            return query(l,mid,T[x].l,T[y].l,pos);
        else return query(mid+1,r,T[x].r,T[y].r,pos - sum); 
    }
    int main(){
        int t;
        scanf("%d",&t);
        while(t--)
        {
            init();
            scanf("%d%d",&n,&m);
            for(int i=1; i<=n; i++)
            {
                scanf("%d", &a[i]);
                v.pb(a[i]);
            }
            sort(v.begin(), v.end());
            v.erase(unique(v.begin(),v.end()),v.end());
    
            for(int i=1; i<=n; i++)
                update(1,n,root[i],root[i-1],getid(a[i]));
            for(int i=1; i<=m; i++)
            {
                int le,ri,k;
                scanf("%d%d%d", &le,&ri,&k);
                printf("%d
    ",v[query(1,n,root[le-1],root[ri],k)-1]);
            }
        }
        return 0;
    }

    POJ的

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <vector>
    using namespace std;
    #define pb push_back 
    const int maxn = 100009;
    
    struct node {
        int l,r;
        int sum;
    }T[maxn*40];
    int a[maxn],root[maxn];
    vector<int>v;
    int getid(int x){
        return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
    }
    int n,m,cnt,x,y,k;
        
    void update(int l,int r,int &x,int y,int pos)
    {
        T[++cnt] = T[y]; T[cnt].sum++; x = cnt;
        if(l==r)return;
        int mid = (l+r)>>1;
        if(mid>=pos)
            update(l,mid,T[x].l,T[y].l,pos);
        else update(mid+1,r,T[x].r,T[y].r,pos);
    }
            
    int query(int l,int r,int x,int y,int pos)
    {
        if(l==r)return l;
        int sum = T[T[y].l].sum - T[T[x].l].sum;
        int mid = (l+r)>>1;
        if(sum >= pos)
            return query(l,mid,T[x].l,T[y].l,pos);
        else return query(mid+1,r,T[x].r,T[y].r,pos - sum); 
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d", &a[i]);
            v.pb(a[i]);
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
    
        for(int i=1; i<=n; i++)
            update(1,n,root[i],root[i-1],getid(a[i]));
        for(int i=1; i<=m; i++)
        {
            int le,ri,k;
            scanf("%d%d%d", &le,&ri,&k);
            printf("%d
    ",v[query(1,n,root[le-1],root[ri],k)-1]);
        }
    
        return 0;
    }
  • 相关阅读:
    JavaEE基础(01):Servlet实现方式,生命周期执行过程
    Spring 框架基础(06):Mvc架构模式简介,执行流程详解
    Spring 框架基础(05):事务管理机制,和实现方式
    多线程搜索与排序
    mybatis的Mapper代理原理
    spring的RestTemplate使用指南
    探索CAS无锁技术
    两年Java的面试经验
    HashMap多线程并发的问题
    解析Mybaits的insert方法返回数字-2147482646的原因
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/8982088.html
Copyright © 2011-2022 走看看