线段树 HDU 3308
t
题目大意:给你n个数,m个操作。操作有两种:1.U x y 将数组第x位变为y 2. Q x y 问数组第x位到第y位连续最长子序列的长度。对于每次询问,输出一个答案
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define MAXN 100010 struct node { int l,r,ls,rs,ms;//维护从左边开始 最大 到右边结束 3个最长上升子序列个数 }x[MAXN<<3]; int z[MAXN],a1,b1; void push_up(int a) { int l=x[a].l,r=x[a].r; int mid=(l+r)>>1; x[a].ls=x[a<<1].ls; x[a].rs=x[a<<1|1].rs; x[a].ms=max(x[a<<1].ms,x[a<<1|1].ms);//这三条是显然的 if(z[mid]<z[mid+1])//成立的话就要合并 { if(x[a].ls==mid-l+1)//左边满 右孩子也左边要加上去 x[a].ls+=x[a<<1|1].ls; if(x[a].rs==r-mid) //同理 x[a].rs+=x[a<<1].rs; x[a].ms=max(x[a].ms,x[a<<1].rs+x[a<<1|1].ls);//中间那段 } } void Build(int l,int r,int a) { x[a].l=l; x[a].r=r; if(l==r) { x[a].ls=x[a].rs=x[a].ms=1; return ; } int mid=(l+r)>>1; Build(l,mid,a<<1); Build(mid+1,r,a<<1|1); push_up(a); } void add(int l,int r,int a1,int a)//其实就是更新操作 { if(l==r) return ; int mid=(l+r)>>1; if(a1<=mid) add(l,mid,a1,a<<1); else add(mid+1,r,a1,a<<1|1); push_up(a); } int Ques(int l,int r,int a1,int b1,int a) { if(a1<=l&&r<=b1) return x[a].ms; int mid=(l+r)>>1; if(b1<=mid) return Ques(l,mid,a1,b1,a<<1); if(a1>mid) return Ques(mid+1,r,a1,b1,a<<1|1); int t1=Ques(l,mid,a1,b1,a<<1); int t2=Ques(mid+1,r,a1,b1,a<<1|1); int ans=max(t1,t2);//上面应该都能看懂 if(z[mid]<z[mid+1])//这边合并可能成为答案 ans=max(ans,min(b1-mid,x[a<<1|1].ls)+min(x[a<<1].rs,mid-a1+1));//如果x[a<<1|1].ls+mid>b1 那么查询范围就变大的了 所哟要取下min 左边同理 return ans; } int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&z[i]); Build(1,n,1); while(m--) { char s[10]; int a,b; scanf("%s%d%d",s,&a,&b);//变成从1开始 a++; if(s[0]=='U') { z[a]=b; add(1,n,a,1);//其实就是一个更新操作 } else { b++; printf("%d\n",Ques(1,n,a,b,1));//查询 } } } return 0; }
posted on 2016-12-23 19:36 HelloWorld!--By-MJY 阅读(153) 评论(0) 编辑 收藏 举报