【权值线段树】

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

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

为什么要用它
我们可以用它来维护一段区间的数出现的次数,从它的定义上来看,它可以快速计算一段区间的数的出现次数。
此外,它还有一个重要功能,在于它可以快速找到第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]);}
        }
    }
}

  

posted on 2019-09-14 10:14  师姐的迷弟  阅读(179)  评论(0编辑  收藏  举报

导航