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

    学习权值线段树,首先要了解线段树是什么。如果不会的可以先学习一下。

    是什么
    权值线段树,顾名思义是一棵线段树。
    但它和普通线段树不同:
    线段树,每个节点用来维护一段区间的最大值或总和等。
    权值线段树,相当于一个桶,每个节点用来表示一个区间的数***出现的次数***。

    为什么要用它
    我们可以用它来维护一段区间的数出现的次数,从它的定义上来看,它可以快速计算一段区间的数的出现次数。
    此外,它还有一个重要功能,在于它可以快速找到第k kk大或第k kk小值,下面会做详细解释。
    其实,它就是一个桶,桶能做到的它都可以用更快的速度去完成。

    基本操作
    添加
    和普通线段树类似,递归到叶子节点时给f[v]+1 f[v]+1f[v]+1。
    以下代码要添加的数是x xx,也就是x xx出现的次数+1 +1+1。

    一道简单模板题;

    也记记吧,免得脑子不灵光又忘记了。

    洛谷 1168

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+5;
    int n;
    int a[N],b[N];
    struct Tree
    {
    int l,r,mid;
    int num;
    }tree[N<<2];
    int read()
    {
    char c=getchar();int num=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
    num=num*10+c-'0';
    return num;
    }
    void build(int root,int l,int r)
    {
    tree[root].l=l,tree[root].r=r,tree[root].mid=l+r>>1;
    if(l==r)
    return;
    build(root<<1,l,tree[root].mid);
    build(root<<1|1,tree[root].mid+1,r);
    }
    void update(int root,int x)
    {
    ++tree[root].num;
    if(tree[root].l==tree[root].r)
    return;
    if(x<=tree[root].mid)
    update(root<<1,x);
    else
    update(root<<1|1,x);
    }
    int query(int root,int num)
    {
    if(tree[root].l==tree[root].r)
    return tree[root].l;
    if(num<=tree[root<<1].num)
    return(query(root<<1,num));
    else
    return(query(root<<1|1,num-tree[root<<1].num));
    }
    int main()
    {
    n=read();
    for(int i=1;i<=n;++i)
    a[i]=read(),b[i]=a[i];
    sort(b+1,b+n+1);
    int bound=unique(b+1,b+n+1)-b;
    build(1,1,n);
    for(int i=1;i<=n;++i){
    int pos=lower_bound(b+1,b+bound+1,a[i])-b;
    update(1,pos);
    if(i%2)
    printf("%d\n",b[query(1,i/2+1)]);
    }
    return 0;
    }

    hdu 6703 array

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=6703

    题目大意:

    给出一个n(n<1e5)个元素的数组A,A中所有元素都是不重复的[1,n]。

    有两种操作:

    1.将pos位置的元素+1e7

    2.查询不属于[1,r]中的最小的>=k的值。

    强制在线,上次计算结果和输入值xor得到区间。

    比赛的时候感觉这道题有点线段树的感觉,和前段时间多校训练一个题很像,想了40多分钟才理想清思路。

    解法:

      可以看出,执行1操作的时候加的数非常大,可以得出每次输出的答案在为1到n+1之间。可以将1-n的每个数在数组A中的位置记录下,存在线段树中,维护线段树区间最大值。

      当执行2操作时,只需要查询区间[k,n]中大于r的值即可,找出最小的数字,先搜索左子树,若无答案搜索右子树,若两侧均无解则答案为n+1。

      当执行1操作时,由于pos+1e7,因此之后的数组中不存在该数,将第pos位的数字在线段树中的值转换为inf即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxx=100005;
    const int inf=0x3f3f3f3f;
    int T,n,m,a[maxx],c[maxx],r,k,x,ans;
    struct node
    {
        int l,r,v;
    }Tr[maxx*4];
    void build(int id,int l,int r)
    {
        Tr[id].l=l,Tr[id].r=r;
        if(l==r){Tr[id].v=c[l];return;}
        int mid=(l+r)/2;
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        Tr[id].v=max(Tr[id*2].v,Tr[id*2+1].v);
    }
    void update(int id,int num)
    {
        if(Tr[id].l==Tr[id].r) {Tr[id].v=inf;return;}
        int mid=(Tr[id].l+Tr[id].r)/2;
        if(num<=mid)update(id*2,num);
        else update((id*2+1),num);
        Tr[id].v=max(Tr[id*2].v,Tr[id*2+1].v);
    }
    int query(int id,int r,int k)
    {
        if(Tr[id].l==Tr[id].r){
            if(Tr[id].v>r) return Tr[id].l;
            else return -1;
        }
        int mid=(Tr[id].l+Tr[id].r)/2,ans=-1;
        if(mid>=k&&Tr[id*2].v>r) ans=query(id*2,r,k);
        if(ans!=-1) return ans;
        else if(Tr[id*2+1].r>=k&&Tr[id*2+1].v>r) ans=query(id*2+1,r,k);
        return ans;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--){
            ans=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]),c[a[i]]=i;
            build(1,1,n);
            while(m--){
    
                scanf("%d",&x);
                if(x==2){scanf("%d %d",&r,&k);ans=query(1,r^ans,k^ans);if(ans==-1)ans=max(n+1,k);printf("%d\n",ans);}
                else{scanf("%d",&x);update(1,a[x^ans]);}
            }
        }
    }
    

      

  • 相关阅读:
    斐波那契数列 的两种实现方式(Java)
    单链表反转
    单链表合并
    两个有序list合并
    list去重 转载
    RemoveAll 要重写equals方法
    Java for LeetCode 138 Copy List with Random Pointer
    Java for LeetCode 137 Single Number II
    Java for LeetCode 136 Single Number
    Java for LeetCode 135 Candy
  • 原文地址:https://www.cnblogs.com/hgangang/p/11518468.html
Copyright © 2011-2022 走看看