考虑建权值线段树,那么线段树存的值就是它的坐标,考虑到答案一定存在且最大值为
n
+
1
n+1
n+1,可以多加一个点
n
+
1
n+1
n+1
对于操作1
(
1
,
x
)
(1,x)
(1,x),直接单点修改位置
s
[
x
]
s[x]
s[x] 为
n
+
1
n+1
n+1(s[x]为初始位置x的值)
对于操作2
(
2
,
r
,
x
)
(2,r,x)
(2,r,x),要查询区间
[
x
,
n
+
1
]
[x,n+1]
[x,n+1]内第一个大于
r
r
r的位置,考虑建一棵维护最大值的线段树,比赛时候第一次写这种问题,当时的思路是,查询时先访问左子树,假如左子树不行才访问右子树,但是这个时候的复杂度是
l
o
g
(
n
)
∗
l
o
g
(
n
)
log(n)*log(n)
log(n)∗log(n),然后开始yy各种剪枝,最后有用的剪枝是当查询的区间包含现在的区间时,可以直接判断符不符合情况,这样可以把多的
l
o
g
(
n
)
log(n)
log(n)变成常数
int query(int p,int l,int r,int x,int y,int tmp)//query(1,1,n+1,x,n+1,r)
{
if(l == r)//查询到叶子节点
{
if(tr[p] > tmp)
{
return l;
}
else
{
return -1;
}
}
if(x <= l && r <= y)//区间包含于查询区间
{
if(tr[p] <= tmp)
{
return -1;
}
}
int mid = (l+r)/2;
if(y <= mid)
{
return query(p*2,l,mid,x,y,tmp);
}
if(x >= mid + 1)
{
return query(p*2+1,mid+1,r,x,y,tmp);
}
int judge = query(p*2,l,mid,x,y,tmp);//先判断左子树
if(judge != -1)
{
return judge;
}
return query(p*2+1,mid+1,r,x,y,tmp);
}