【bzoj4491】【我也不知道题目名字是什么】【线段树】

Description

给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串

Input

第一行n,表示A数组有多少元素
接下来一行为n个整数A[i]
接下来一个整数Q,表示询问数量
接下来Q行,每行2个整数l,r

Output

对于每个询问,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串

Sample Input

9
1 2 3 4 5 6 5 4 3
5
1 6
1 7
2 7
1 9
5 9

Sample Output

6
6
5
6
4


样例解释
五个询问分别对应
[1,6][1,6][2,6][1,6][6,9]

HINT

N,Q<=50000

题解:线段树维护左边上升,下降,权值和右边上升,下降,权值以及区间长,最大值即可。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define N 50010
using namespace std;
struct use{int lup,rup,ldown,rdown,lv,rv,len,mxup,mxdown;}t[N<<2];
int n,x,y,a[N],q;
use update(use a,use b){
  use c;
  c.len=a.len+b.len;
  c.lv=a.lv;c.rv=b.rv;
  c.lup=a.lup;
  if (a.lup==a.len&&a.rv<=b.lv) c.lup=a.len+b.lup;
  c.ldown=a.ldown; 
  if (a.ldown==a.len&&a.rv>=b.lv) c.ldown=a.len+b.ldown;
  c.rup=b.rup;
  if (b.rup==b.len&&b.lv>=a.rv) c.rup=b.len+a.rup;
  c.rdown=b.rdown;
  if (b.rdown==b.len&&b.lv<=a.rv) c.rdown=b.len+a.rdown;
  c.mxup=max(a.mxup,b.mxup);
  if (a.rv<=b.lv) c.mxup=max(c.mxup,a.rup+b.lup);
  c.mxdown=max(a.mxdown,b.mxdown);
  if (a.rv>=b.lv) c.mxdown=max(c.mxdown,a.rdown+b.ldown);
  return c;
}
void build(int k,int l,int r){
  int mid=(l+r)>>1;
  if (l==r){
    t[k].lv=t[k].rv=a[l];
    t[k].lup=t[k].rup=t[k].ldown=t[k].rdown=t[k].len=t[k].mxup=t[k].mxdown=1;
    return;
  }
  build(k<<1,l,mid);
  build(k<<1|1,mid+1,r);
  t[k]=update(t[k<<1],t[k<<1|1]);
}
use query(int k,int l,int r,int ll,int rr){ 
  if (l==ll&&r==rr){return t[k];}
  int mid=(l+r)>>1;
  if (rr<=mid) return query(k<<1,l,mid,ll,rr);
  else if (mid<ll) return query(k<<1|1,mid+1,r,ll,rr);
  else return update(query(k<<1,l,mid,ll,mid),query(k<<1|1,mid+1,r,mid+1,rr)); 
}
int main(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++) scanf("%d",&a[i]);
  scanf("%d",&q);
  build(1,1,n);	
  for (int i=1;i<=q;i++){
    scanf("%d%d",&x,&y);
    use a=query(1,1,n,x,y);
    printf("%d\n",max(a.mxup,a.mxdown));
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值