链接:HDU6703 - array
给出 n n n个数的数组 a 1 , a 2 , ⋯   , a n    ( ∀ i ∈ [ 1 , n ] , 1 ≤ a i ≤ n ≤ 1 0 5 ) a_1,a_2,\cdots,a_n\;(∀i∈[1,n],1≤a_i≤n\le10^5) a1,a2,⋯,an(∀i∈[1,n],1≤ai≤n≤105),其中 a a a各不相同。
给出 m    ( 1 ≤ m ≤ 1 0 5 ) m\;(1≤m≤10^5) m(1≤m≤105)个操作,分为 2 2 2种:
根据数组 a a a建立权值线段树,里面存储各个权值在数组 a a a的位置,由于询问的最小整数要不等于 a 1 , a 2 , ⋯   , a r a_1,a_2,\cdots,a_r a1,a2,⋯,ar中任意一个数,所以不等于 a a a的权值的位置应初始化为 > n \gt n >n(如 n + 1 n+1 n+1),这样就不会被排除。
查询时只需要查询权值 [ k , n ] [k,n] [k,n]中最小的且位置 > r \gt r >r的权值,如果没找到,则答案一定是 n + 1 n+1 n+1(可以想象该情况就是数组 a a a将 1 1 1~ n n n的权值恰好填满了)。
对于令 a p o s = a p o s + 1 0 7 a_{pos}=a_{pos}+10^7 apos=apos+107,由于 1 0 7 10^7 107足够大,则可以直接将 a p o s a_{pos} apos删去即可(令权值 a p o s a_{pos} apos的位置变为 > n \gt n >n)。
关键是在权值线段树中的查询操作,权值线段树记录 区间中的最大位置,这样就可以判断左、右区间内存不存在最大位置 > r \gt r >r。
遍历到线段树的一个结点,若左子树存在最大位置 > r \gt r >r,则优先向左子树遍历,但是左子树不一定有答案(因为是左子树,所以位置 > r \gt r >r的权值不一定 ≥ k \ge k ≥k);若左子树没答案,再判断右子树的是否存在最大位置 > r \gt r >r,若存在,则答案一定在右子树(因为是左子树,所以位置 > r \gt r >r的权值一定 ≥ k \ge k ≥k),若不存在,则不要遍历右子树。
那么这样剪枝后,最坏的情况也只有 O ( 2 log n ) O(2\log n) O(2logn)。
#include
#define LL long long
using namespace std;
const int MOD=998244353;
const int INF=0x3f3f3f3f;
const int maxn=1e5+50;
int n,m,a[maxn];
int t[maxn<<2];
void build(int rt,int l,int r)
{
if(l==r)
{
t[rt]=n+1;
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
void updata(int rt,int l,int r,int val,int pos)
{
if(l==r)
{
t[rt]=pos;
return;
}
int mid=(l+r)>>1;
if(val<=mid)
updata(rt<<1,l,mid,val,pos);
else
updata(rt<<1|1,mid+1,r,val,pos);
t[rt]=max(t[rt<<1],t[rt<<1|1]);
}
int query(int rt,int l,int r,int k,int lim)
{
if(l==r)
{
if(t[rt]>lim)
return l;
else
return n+1;
}
int mid=(l+r)>>1;
int ans=n+1;
if(k<=mid&&t[rt<<1]>lim)
ans=query(rt<<1,l,mid,k,lim);
if(ans==n+1&&t[rt<<1|1]>lim)
ans=query(rt<<1|1,mid+1,r,k,lim);
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
build(1,1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
updata(1,1,n,a[i],i);
}
int op,pos,r,k;
int ans=0;
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d",&pos);
pos^=ans;
updata(1,1,n,a[pos],n+1);
}
else
{
scanf("%d %d",&r,&k);
r^=ans;
k^=ans;
ans=query(1,1,n,k,r);
printf("%d\n",ans);
}
}
}
return 0;
}