hdu 3308 LCIS(线段树)(第三部分 区间合并)

来源:互联网 发布:python 日期加一 编辑:程序博客网 时间:2024/05/16 19:35

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308

题目大意:给你n个数,m个操作。

操作有两种:

1.U x y 将数组第x位变为y 

2. Q x y 问数组第x位到第y位连续最长子序列的长度。

对于每次询问,输出一个答案

思路:

一:存线段树数据的数组要有四个变量。

lsum 存的是从本节点区间最左端开始(向右)连续上升序列的长度

rlsum 存的是 从本节点区间最右端开始(向左)连续上升序列的长度

msum存的是 本区间连续上升序列的最大长度

sum[rt][0]存的是这个区间最左边的那个数 sum[rt][0]存的是这个区间最右边的那个数

二:关于pushup函数

void pushup(int rt,int m)//向上传递{lsum[rt]=lsum[rt<<1];rsum[rt]=rsum[rt<<1|1];if(lsum[rt]==m-(m>>1)&&sum[rt<<1][1]<sum[rt<<1|1][0])lsum[rt]+=lsum[rt<<1|1];if(rsum[rt]==(m>>1)&&sum[rt<<1][1]<sum[rt<<1|1][0])rsum[rt]+=rsum[rt<<1];msum[rt]=max(msum[rt<<1],msum[rt<<1|1]);if(sum[rt<<1][1]<sum[rt<<1|1][0])msum[rt]=max(msum[rt],rsum[rt<<1]+lsum[rt<<1|1]);sum[rt][1]=sum[rt<<1|1][1];sum[rt][0]=sum[rt<<1][0];}

就是当更新树中一节点后  回溯更新该节点的父节点的  lsum   rsum  msum  sum的值。。

我们可以发现 节点 rt 的lsum rsum msum 值是与它左右儿子节点的lsum  rsum  msum值有关系的

 rt 节点的lsum 值  等于 他左儿子的lsum值 ,如果左儿子区间整个序列都是一个上升子序列,并且左儿子最右边的数大于右儿子最左边的数,那么lsum的值等于 左儿子的lsum值 + 右儿子的lsum值  具体参考代码理解

同理:rsum值也一样……

对于 rt 节点 的msum值等于  Max( 左儿子的msum值,右儿子的msum值 )

如果左儿子最右边的数大于右儿子最左边的数,那么Max( 左儿子的msum值,右儿子的msum值 ,左儿子的rsum值+右儿子的lsum值)

三:关于query函数

int query(int L,int R,int l,int r,int rt){if(L<=l&&r<=R){return msum[rt];}int m=(r+l)>>1;if(L>m)return query(L,R,rson);if(R<=m)return query(L,R,lson);int res1,res2,res3;res1=query(L,R,lson);res2=query(L,R,rson);res3=max(res1,res2);if(sum[rt<<1][1]<sum[rt<<1|1][0])res3=max(res3,(min(lsum[rt<<1|1],R-m)+min(rsum[rt<<1],m-L+1)));return res3;}
这边需要注意的就是
res3=max(res3,(min(lsum[rt<<1|1],R-m)+min(rsum[rt<<1],m-L+1)));
理解下为什么要取最小值,因为lsum[rt<<1|1]这是对于他右边这个大的区间的,我们还需要考虑他所给出的范围,即右边应该小于R,左边应该大于等于L!!!即右边最大为R-m,左边最大为m-L+1


接下来直接上AC代码:

#include<iostream>#include<cmath>#include<cstdio>#include<iomanip>#include<cstring>#include<stdlib.h>#include<string>#include<algorithm>#include<queue>using namespace std;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1const int  maxn =110000;int sum[maxn<<2][2];int lsum[maxn<<2],rsum[maxn<<2],msum[maxn<<2];void pushup(int rt,int m)//向上传递{lsum[rt]=lsum[rt<<1];rsum[rt]=rsum[rt<<1|1];if(lsum[rt]==m-(m>>1)&&sum[rt<<1][1]<sum[rt<<1|1][0])lsum[rt]+=lsum[rt<<1|1];if(rsum[rt]==(m>>1)&&sum[rt<<1][1]<sum[rt<<1|1][0])rsum[rt]+=rsum[rt<<1];msum[rt]=max(msum[rt<<1],msum[rt<<1|1]);if(sum[rt<<1][1]<sum[rt<<1|1][0])msum[rt]=max(msum[rt],rsum[rt<<1]+lsum[rt<<1|1]);sum[rt][1]=sum[rt<<1|1][1];sum[rt][0]=sum[rt<<1][0];}void build(int l,int r,int rt){if(l==r){lsum[rt]=rsum[rt]=msum[rt]=1;scanf("%d",&sum[rt][0]);sum[rt][1]=sum[rt][0];return ;}int m=(l+r)>>1;build(lson);build(rson);pushup(rt,r-l+1);}int query(int L,int R,int l,int r,int rt){if(L<=l&&r<=R){return msum[rt];}int m=(r+l)>>1;if(L>m)return query(L,R,rson);if(R<=m)return query(L,R,lson);int res1,res2,res3;res1=query(L,R,lson);res2=query(L,R,rson);res3=max(res1,res2);if(sum[rt<<1][1]<sum[rt<<1|1][0])res3=max(res3,(min(lsum[rt<<1|1],R-m)+min(rsum[rt<<1],m-L+1)));return res3;}void update(int p,int c,int l,int r,int rt){if(p==l&&p==r){sum[rt][0]=sum[rt][1]=c;return ;}int m=(r+l)>>1;if(p<=m)update(p,c,lson);else if(p>m)update(p,c,rson);pushup(rt,r-l+1);}int main(){int n,m;int t;scanf("%d",&t);while(t--){memset(sum,0,sizeof sum);scanf("%d%d",&n,&m);build(1,n,1);while(m--){char op[5];int a,b;scanf("%s",op);if(op[0]=='Q')//查询住房{scanf("%d%d",&a,&b);int p=query(a+1,b+1,1,n,1);printf("%d\n",p);}else{scanf("%d%d",&a,&b);update(a+1,b,1,n,1);}}}return 0;}