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

    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
    ",ans);
    			}
    		}
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    P2480 [SDOI2010]古代猪文(CRT+Lucas+费马小定理)
    P2473 [SCOI2008]奖励关(状压+期望dp)
    P2485 [SDOI2011]计算器(快速幂+扩欧+bsgs)
    板子
    https://lydsy.download/archive/
    [SDOI2010]地精部落(dp)
    P2446 [SDOI2010]大陆争霸(有限制的最短路)
    博客园在页面内设置超链接
    Matlab 绘制双纵轴图
    Matlab画图线型、符号及颜色汇总
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/11406186.html
Copyright © 2011-2022 走看看