标签:线段树
1 10 10 7 7 3 3 5 9 9 8 1 8 Q 6 6 U 3 4 Q 0 1 Q 0 5 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9
1 1 4 2 3 1 2 5
这题属于线段树区间合并,题意是求一个区间内的最长连续递增子序列。首先用线段树维护7个节点,l,r,llen,rlen,tlen,lnum,rnum;(llen,rlen表示这段区间从最左(右)向右(左)可以持续的最大递增子序列长度。tlen表示这条线段的最大递增子序列长度,lnum,rnum表示这段线段最左边和左右边的值)。我在一开始建树的时候就把7个初始化好了,这样下面就比较方便。
这里的难点是查询,当查询区间全落在左子树或者右子树的时候比较简单,直接算子树的最大长度,但落在中间的时候要考虑合并的值,这里合并时注意不能直接用b[i*2].rlen+b[i*2+1].llen,因为查询的区间(l,r)可能大于b[2*i+1].l+b[2*i+1].llen-1或者小于b[2*i].r-b[2*i].rlen+1,这样就要分类讨论。这里卡了很长时间= =。
#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; int a[100005],num; char s[10]; struct node{ int l,r,llen,rlen,tlen,lnum,rnum; }b[8*100005]; int max(int a,int b){ return a>b?a:b; } void build(int l,int r,int i) { int mid; b[i].l=l;b[i].r=r; if(l==r){ b[i].lnum=b[i].rnum=a[l]; b[i].rlen=b[i].llen=b[i].tlen=1; return; } mid=(l+r)/2; build(l,mid,i*2); build(mid+1,r,i*2+1); b[i].lnum=b[i*2].lnum; b[i].rnum=b[i*2+1].rnum; b[i].tlen=max(b[i*2].tlen,b[i*2+1].tlen); if(b[i*2].rnum<b[i*2+1].lnum){ b[i].tlen=max(b[i].tlen,b[i*2].rlen+b[i*2+1].llen); } b[i].llen=b[i*2].llen; if(b[i*2].rnum<b[i*2+1].lnum && b[i*2].llen==(b[i*2].r-b[i*2].l+1)){ b[i].llen+=b[i*2+1].llen; } b[i].rlen=b[i*2+1].rlen; if(b[i*2].rnum<b[i*2+1].lnum && b[i*2+1].rlen==(b[i*2+1].r-b[i*2+1].l+1)){ b[i].rlen+=b[i*2].rlen; } } void update(int index,int num,int i) { int mid; if(b[i].l==b[i].r){ b[i].rnum=b[i].lnum=num;return; } if(b[i*2].r-b[i*2].l+1>=index)update(index,num,i*2); else update(index-(b[i*2].r-b[i*2].l+1),num,i*2+1); b[i].lnum=b[i*2].lnum; b[i].rnum=b[i*2+1].rnum; b[i].tlen=max(b[i*2].tlen,b[i*2+1].tlen); if(b[i*2].rnum<b[i*2+1].lnum){ b[i].tlen=max(b[i].tlen,b[i*2].rlen+b[i*2+1].llen); } b[i].llen=b[i*2].llen; if(b[i*2].rnum<b[i*2+1].lnum && b[i*2].llen==(b[i*2].r-b[i*2].l+1)){ b[i].llen+=b[i*2+1].llen; } b[i].rlen=b[i*2+1].rlen; if(b[i*2].rnum<b[i*2+1].lnum && b[i*2+1].rlen==(b[i*2+1].r-b[i*2+1].l+1)){ b[i].rlen+=b[i*2].rlen; } } void question(int l,int r,int i) { int mid,r1,l1; if(b[i].l==l && b[i].r==r){ num=max(num,b[i].tlen);return; } mid=(b[i].l+b[i].r)/2; if(r<=mid)question(l,r,i*2); else if(l>mid)question(l,r,i*2+1); else if(l<=mid && r>mid){ if(b[i*2].rnum<b[i*2+1].lnum){ if(b[2*i+1].l+b[2*i+1].llen-1>=r)r1=r; else r1=b[2*i+1].l+b[2*i+1].llen-1; if(b[2*i].r-b[2*i].rlen+1<=l)l1=l; else l1=b[2*i].r-b[2*i].rlen+1; num=max(num,r1-l1+1); } question(l,mid,i*2); question(mid+1,r,i*2+1); } } int main() { int n,m,i,j,T,c,d; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ scanf("%d",&a[i]); } build(1,n,1); for(i=1;i<=m;i++){ scanf("%s",s); if(s[0]=='Q'){ scanf("%d%d",&c,&d); num=0; question(c+1,d+1,1); printf("%d\n",num); } else if(s[0]=='U'){ scanf("%d%d",&c,&d); update(c+1,d,1); } } } return 0; }
标签:线段树
原文地址:http://blog.csdn.net/kirito_acmer/article/details/46013769