标签:
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
题解:求区间连续递增的最大个数,用到了线段树的区间合并。每个节点保存了该区间的最大递增数,该区间的左值和右值,这两个变量用来判断两个孩子节点构成的递增
序列,再通过左孩子的最右端的最大递减序列+右孩子的最左端的最大递增序列,就可以更新父节点的最大递增序列了。自己画图好好体会就行了。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; struct Node { int l,r; //左右区间 int ln,rn; //区间的左值和右值,因为需要拿来和其他区间比较是不是能构成连续递增序列 int ls,rs,ms; //左值的最大连续递增个数和右值最大连续递减个数,和该区间最大连续递增个数 }; Node arr[400005]; int a[100005]; int max(int x,int y) { return x > y ? x : y; } int min(int x,int y) { return x > y ? y : x; } void pushUp(int k) //将父节点的变量更新,因为儿子节点都知道了 { int li = k << 1; int ri = (k << 1) | 1; int mid = (arr[k].l + arr[k].r) >> 1; arr[k].ln = arr[li].ln; arr[k].rn = arr[ri].rn; arr[k].ls = arr[li].ls; arr[k].rs = arr[ri].rs; arr[k].ms = max(arr[li].ms,arr[ri].ms); //取孩子较大的序列 if(arr[li].rn < arr[ri].ln) //如果左孩子的最右边的值小于右孩子的最左边的值 { //计算这个序列 if(arr[li].ls == arr[li].r - arr[li].l + 1) //更新左递增序列 { arr[k].ls += arr[ri].ls; } if(arr[ri].ls == arr[ri].r - arr[ri].l + 1) //更新右递减序列 { arr[k].rs += arr[li].rs; } arr[k].ms = max(arr[k].ms,arr[li].rs + arr[ri].ls); //得到最大连续递增序列个数 } } void segTree(int k,int l,int r) { arr[k].l = l; arr[k].r = r; if(l == r) { arr[k].ln = arr[k].rn = a[l]; arr[k].ls = arr[k].rs = arr[k].ms = 1; return; } int mid = (l + r) >> 1; segTree(k << 1,l,mid); segTree((k << 1) | 1,mid + 1,r); pushUp(k); //更新父节点 } void insert(int k,int x,int y) { if(arr[k].l == arr[k].r) { arr[k].ln = arr[k].rn = y; return; } int mid = (arr[k].l + arr[k].r) >> 1; if(x > mid) { insert((k << 1) | 1,x,y); } else { insert(k << 1,x,y); } pushUp(k); } int query(int k,int l,int r) { if(arr[k].l == l && arr[k].r == r) { return arr[k].ms; } int li = k << 1; int ri = (k << 1) | 1; int mid = (arr[k].l + arr[k].r) >> 1; if(l > mid) { return query(ri,l,r); } if(r <= mid) { return query(li,l,r); } int t1 = query(li,l,mid); int t2 = query(ri,mid + 1,r); int t3 = 0; if(arr[li].rn < arr[ri].ln) //左孩子和右孩子还能构成递增序列 { t3 = min(mid - l + 1,arr[li].rs) + min(r - mid,arr[ri].ls); //找到左孩子右递减部分和右孩子左递增部分 } return max(max(t1,t2),t3); //取最大值 } int main() { int T; cin>>T; while(T--) { int n,m; scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); } segTree(1,1,n); //建树 char ch[3]; int l,r; for(int i = 0;i < m;i++) { scanf("%s%d%d",ch,&l,&r); if(ch[0] == 'Q') { printf("%d\n",query(1,l + 1,r + 1)); //下标从1开始算 } else { insert(1,l + 1,r); } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/wang2534499/article/details/47363339