http://acm.hdu.edu.cn/showproblem.php?pid=3308
大意:输入n个数,m个操作。操作有两种:1.U x y 将数组第x位变为y 2. Q x y 问数组第x位到第y位连续最长子序列的长度。
题目主要考察的就是对pushup逆向更新的运用,就是更改树底(1号操作),从树底下往上更新。。。
至于最长子序列,长度为1的区间最长子序列当然就是自己,对于两个区间的最长子序列合并,无非就是两种情况,一种就是两个区间的最长子序列接上了,第二种就是没接上,取两个最长子序列的最大值
我的程序,用a[i].l保存区间左端,a[i].r保存区间右端,a[i].c保存区间长度(就是l-r+1),a[i].ln保存区间里的最长子序列的左端有多大,a[i].rn保存区间里的最长子序列的右端有多大,a[i].ls保存最长子序列左端位置,a[i].rs保存最长子序列右端位置,a[i].ms保存最长子序列长度(就是a[i].rs-a[i].ls+1)
然后就是合并咯
我的程序(可能是优化不到位,能过很多数据但到hdu上评测会超时,也许过几天就能把这个括号删掉了)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define L 100010 int n,m,s[L]; struct node { int l,r,c; int ln,rn; int ls,rs,ms; } a[L<<2]; void pushup(int i) { a[i].ls = a[2*i].ls; a[i].rs = a[2*i+1].rs; a[i].ln = a[2*i].ln; a[i].rn = a[2*i+1].rn; a[i].ms = max(a[2*i].ms,a[2*i+1].ms); if(a[2*i].rn<a[2*i+1].ln) { if(a[2*i].ls == a[2*i].c) a[i].ls+=a[2*i+1].ls; if(a[2*i+1].rs == a[2*i+1].c) a[i].rs+=a[2*i].rs; a[i].ms = max(a[i].ms,a[2*i].rs+a[2*i+1].ls); } } void init(int l,int r,int i) { a[i].l=l; a[i].r=r; a[i].c=r-l+1; if(l==r) { a[i].ln=a[i].rn=s[l]; a[i].ls=a[i].rs=a[i].ms=1; return; } int k=(a[i].l+a[i].r)>>1; init(l,k,2*i); init(k+1,r,2*i+1); pushup(i); } void insert(int i,int t,int m) { if(a[i].l == a[i].r) { a[i].ln = a[i].rn = m; return; } int k = (a[i].l+a[i].r)>>1; if(t<=k) insert(2*i,t,m); if(t>k) insert(2*i+1,t,m); pushup(i); } int search(int l,int r,int i) { if(a[i].l>=l && a[i].r<=r) { return a[i].ms; } int k = (a[i].l+a[i].r)>>1,sum = 0; if(l<=k) sum=max(sum,search(l,r,2*i)); if(r>k) sum=max(sum,search(l,r,2*i+1)); if(a[2*i].rn<a[2*i+1].ln) sum = max(sum , min(k-l+1,a[2*i].rs)+min(r-k,a[2*i+1].ls)); return sum; } int main() { int t,i,l,r; char str[5]; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); for(i=1; i<=n; i++) scanf("%d",&s[i]); init(1,n,1); while(m--) { scanf("%s%d%d",str,&l,&r); if(str[0] == 'Q') printf("%d\n",search(l+1,r+1,1)); else insert(1,l+1,r); } } return 0; }