hdu 3308(线段树的区间合并)

题目链接: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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值