给出一列数,有两种操作:
1.修改一个数
2.询问区间最大值
用树状数组来维护区间最值,复杂度为O(n*(logn)^2).
做法与维护区间和不同,因为修改最值时无法求出新的最值,但是维护的区间相同.
树状数组维护的区间是[u-lowbit(u)+1,u],可以据此来进行这些操作.
若sz[i]之前的值都正确,则可以发现C[i]可以用这段代码维护.
for(i=1; ii<<=1)
{
sz[u]=max(sz[u],sz[u-i]);
}
因此只要用这种方法更新所有包含它的区间就行了.
inline void chg(int u,int v)
{
int i;
num[u]=v;
sz[u]=v;
for(; u<=n; u+=lb(u))
{
for(i=1; i1)
{
sz[u]=max(sz[u],sz[u-i]);
}
}
}
根据它维护的范围,若要查询[u,v],则可以根据v-lowbit(v)的值进行讨论:
1.u>v-lowbit(v),答案与num[v]取最值,v–
2.u<=v-lowbit(v),答案与sz[v]取最值,v-=lowbit(v).
如此循环,直至u
inline int ask(int u,int v)
{
int res=0;
for(; u<=v;)
{
res=max(res,num[v]);
v--;
for(; v-lb(v)>=u; v-=lb(v))
{
res=max(res,sz[v]);
}
}
return res;
}
#include
#include
#include
#define C ch=getchar()
#define N 200100
using namespace std;
int n,m,sz[N],num[N];
inline int lb(int u)
{
return u&(-u);
}
inline void chg(int u,int v)
{
int i;
num[u]=v;
sz[u]=v;
for(; u<=n; u+=lb(u))
{
for(i=1; i1)
{
sz[u]=max(sz[u],sz[u-i]);
}
}
}
inline int ask(int u,int v)
{
int res=0;
for(; u<=v;)
{
res=max(res,num[v]);
v--;
for(; v-lb(v)>=u; v-=lb(v))
{
res=max(res,sz[v]);
}
}
return res;
}
int main()
{
int i,j,p,q;
char ch;
while(~scanf("%d%d",&n,&m))
{
memset(sz,0,sizeof(sz));
for(i=1; i<=n; i++)
{
scanf("%d",&num[i]);
chg(i,num[i]);
}
for(i=1; i<=m; i++)
{
for(C; ch!='Q'&&ch!='U'; C);
scanf("%d%d",&p,&q);
if(ch=='Q')
{
printf("%d\n",ask(p,q));
}
else
{
chg(p,q);
}
}
}
}