首页 > 其他 > 详细

权值线段树

时间:2019-08-24 23:35:34      阅读:255      评论:0      收藏:0      [点我收藏+]

array

题意

给出一个1,n的排列,有q(q<=1e5)有以下两个操作(强制在线):
1.给位置pos上的数+1e7
2.询问[1,r]区间上大于等于k(1e5)的数最小是多少(这个数不能等于[1,r]区间中的任意一个数)

分析

由数据我们可以知道只要对一个数进行了操作1,相当于把这个数挖掉了,所以我们想要找到最小的满足题意的值,只需要维护区间最大值,只要区间中有值大于等于k,就可以进区间找,但是这样会带来很多问题,首先是区间全是连续的无法插,其次是可以插,如何找到这个空?这个时候需要转化思维,既然普通线段树难以维护,是否考虑主席树or权值线段树,使用权值线段树,维护区间最大的标号,如果标号大于等于r,先往左边找,但是这样可能会导致[1,mid]中有标号比r大的,但是比k小,这样就会一直找到mid,只需要开一个变量记一下,如果[1,mid]不合法继续到右子树找就行了(比赛的时候心态崩了这么简单处理都不会了,要是冷静下来改改就过了)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+4;
const int inf=0x3f3f3f3f;
int tr[maxn<<2];
int a[maxn],b[maxn],vis[maxn];
void build(int o,int l,int r){
    if(l==r)tr[o]=b[l];
    else {
        int mid=l+r>>1;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        tr[o]=max(tr[o<<1],tr[o<<1|1]);
    }
}
void update(int o,int l,int r,int p){
    if(l==r)tr[o]=inf-1;
    else {
        int mid=l+r>>1;
        if(p<=mid)update(o<<1,l,mid,p);
        else update(o<<1|1,mid+1,r,p);
        tr[o]=max(tr[o<<1],tr[o<<1|1]);
    }
}

int ok=0;
int query(int o,int l,int r,int x,int y,int k){
    //cout<<l<<" "<<r<<endl;
        if(l==r){
            //cout<<tr[o]<<endl;
            if(tr[o]<=y){
                return inf;
            }
            ok=1;
            return l;           
        }
        else {
            int mid=l+r>>1;
            int ans=inf;
            if(k<=mid&&tr[o<<1]>y){
                
                  ans=query(o<<1,l,mid,x,y,k);
                  if(ans!=inf)return ans;
                  else if(ok==0){
                      return query(o<<1|1,mid+1,r,x,y,k);
                  }
            }
            else {
                return query(o<<1|1,mid+1,r,x,y,k);
            }
        }
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int sz=n+2;
        for(int i=1;i<=n+2;i++){
            b[i]=inf-1;
        }
        for(int i=1;i<=n;i++)vis[i]=0;
        for(int i=1;i<=n;i++)b[a[i]]=i;
        build(1,1,sz);
        int pos,r,k;
        int ans=0;
        while(q--){
            int op;
            ok=0;
            scanf("%d",&op);
            if(op==1){
                scanf("%d",&pos);
                pos=pos^ans;
                if(vis[pos]==0)update(1,1,sz,a[pos]),vis[pos]=1;
            }
            else {
                scanf("%d%d",&r,&k);
                r=r^ans;
                k=k^ans;
                 ans=query(1,1,sz,1,r,k);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

权值线段树

原文:https://www.cnblogs.com/ttttttttrx/p/11406186.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!