题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308
题意:给你一串数(最多有10^5个,值最大有10^5),给你两个operation, U x y,表示将第x个值替换为y, Q x y表示查询x到y中最长连续子序列的个数,操作的次数不超过10^5个
分析: 啊,这个题显然用线段树做,我们可以设置线段树的一些域,l,r,lz,rz,mnum,分别表示区间的左右边界,区间左边连续的递增序列个数,区间右边连续测递增序列个数,区间中最大的递增序列的个数,之后就是维护的问题了,详情见代码!!
代码:
#include<stdio.h>
#include<string.h>
#define N 100005
//const int N=100005;
int a[N];
struct node
{
int l,r; //区间的左右边界
int lz,rz;//分别表示左右两边连续的递增递减的序列个数
int mnum; //表示区间里的最大连续的个数
}tree[N*4];
int Max(int a,int b)
{
return a>b?a:b;
}
void bulid(int rt,int l, int r)// 建立线段树,并初始化lz,rz,mnum;
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].lz=0;
tree[rt].rz=0;
tree[rt].mnum=0;
if(l==r)
{
tree[rt].lz=1;//若为根节点那么区间左边界开始的递增数目1
tree[rt].rz=1;//同上
tree[rt].mnum=1;//区间的最大递增数目也为1
return;
}
int mid=(l+r)>>1;
bulid(2*rt,l,mid);//建左子树
bulid(2*rt+1,mid+1,r);//建右子树
//回溯更新区间值
if(tree[2*rt].lz==(mid-l+1)&&a[mid+1]>a[mid])//更新区间左边连续递增序列的个数
tree[rt].lz=tree[2*rt].lz+tree[2*rt+1].lz;
else tree[rt].lz=tree[2*rt].lz;
if(tree[2*rt+1].rz==(r-mid)&&a[mid+1]>a[mid]) //更新区间右边连续递增序列的个数
tree[rt].rz=tree[2*rt+1].rz+tree[2*rt].rz;
else tree[rt].rz=tree[2*rt+1].rz;
tree[rt].mnum=Max(tree[2*rt].mnum,tree[2*rt+1].mnum);//更新区间中最大连续连续递增序列的值
if(a[mid+1]>a[mid])
tree[rt].mnum=Max(tree[2*rt].rz+tree[2*rt+1].lz,tree[rt].mnum);
}
void update(int rt,int x,int y,int l, int r)
{
if(l==r&&x==l)
{
a[x]=y;
return;
}
int mid=(l+r)>>1;
if(x<=mid)
update(2*rt,x,y,l,mid);
else update(2*rt+1,x,y,mid+1,r);
//这里的回溯更新同bulid函数里的一样
if(tree[2*rt].lz==(mid-l+1)&&a[mid+1]>a[mid])
tree[rt].lz=tree[2*rt].lz+tree[2*rt+1].lz;
else tree[rt].lz=tree[2*rt].lz;
if(tree[2*rt+1].rz==(r-mid)&&a[mid+1]>a[mid])
tree[rt].rz=tree[2*rt+1].rz+tree[2*rt].rz;
else tree[rt].rz=tree[2*rt+1].rz;
tree[rt].mnum=Max(tree[2*rt].mnum,tree[2*rt+1].mnum);
if(a[mid+1]>a[mid])
tree[rt].mnum=Max(tree[2*rt].rz+tree[2*rt+1].lz,tree[rt].mnum);
}
//查询结果
int search(int rt,int l,int r)
{
int ans1,ans,ans2 , ans3,ans4;
if(tree[rt].l==l&&tree[rt].r==r)
return tree[rt].mnum;
int mid=(tree[rt].l+tree[rt].r)>>1;
if(r<=mid)return search(2*rt,l,r);
else if(l>mid)return search(2*rt+1,l,r);
else
{
//注意这里
if(tree[2*rt].rz>=mid-l+1)
ans1=mid-l+1;
else ans1=tree[2*rt].rz;
if(tree[2*rt+1].lz>=r-mid)
ans2=r-mid;
else ans2=tree[2*rt+1].lz;
if(a[mid+1]>a[mid])
ans=ans1+ans2;
else ans=0;
ans3=search(2*rt,l,mid);
ans4=search(2*rt+1,mid+1,r);
if(ans)
return Max(ans,Max(ans3,ans4));
return Max(Max(ans1,ans2),Max(ans3,ans4));
}
}
void print(int rt)
{
printf("%d %d %d %d %d\n",tree[rt].l, tree[rt].r,tree[rt].lz, tree[rt].rz,tree[rt].mnum);
if(tree[rt].l==tree[rt].r)
return;
print(2*rt);
print(2*rt+1);
}
int main ()
{
int t,n,q,i,x,y;
char ch[3];
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&q);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
bulid(1,0,n-1);
getchar();
for(i=0;i<q;i++)
{
scanf("%s%d%d",ch,&x,&y);
//printf("%s\n",ch);
if(ch[0]=='Q')
printf("%d\n",search(1,x,y));
else if(ch[0]=='U')
update(1,x,y,0,n-1);
}
}
return 0;
}