HDU 3308 LCIS 线段树 区间更新
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3308
题目描述: 有两种操作, U x y , 第xth赋值为y 。Q x y , 查询区间x-y的最长连续上升子序列的长度L
解题思路: 对于线段树不好的我依然好难.....有太多细节需要注意了....但是这是一道很好的题, 一段区间的L可能从三个地方来, 一种是中间, 一种是以左起点为开头的, 一种是以右起点结尾的, 这样查询的时候就要注意了: 如果两段的中间值是a[m] < a[m+1] 我们就要从这三段中选出一个最大的, 否则就只从前两段中选出最大的. .....然后向上更新的时候要注意: 如果左区间是一个整个的LCIS, 那我们就应该将左区间更新为左区间加上左儿子的右区间, 右区间同理, 我解释的比较拗口......其实这是很巧的 , 我们可以从第一步将数画在纸上构造一遍就会很清楚.....最后BUG当然是不能少的啦........我啥都缺, 就是不缺BUG
代码:
#include <iostream> #include <cstdio> #include <string> #include <vector> #include <cstring> #include <iterator> #include <cmath> #include <algorithm> #include <stack> #include <deque> #include <map> #include <set> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 #define mem0(a) memset(a,0,sizeof(a)) #define sca(x) scanf("%d",&x) #define de printf("=======\n") typedef long long ll; using namespace std; int n, mm, t; const int maxn = 1e5+10; int no[maxn<<2], ls[maxn<<2], rs[maxn<<2]; int a[maxn]; int x, y; inline void pushUp( int l, int r, int rt ) { int m = (l+r) >> 1; ls[rt] = ls[rt<<1]; rs[rt] = rs[rt<<1|1]; no[rt] = max( no[rt<<1], no[rt<<1|1] ); if( a[m] < a[m+1] ) { if(ls[rt] == m-l+1) ls[rt] += ls[rt<<1|1]; if(rs[rt] == r-m) rs[rt] += rs[rt<<1]; no[rt] = max( no[rt], ls[rt<<1|1]+rs[rt<<1] ); } } void build(int l, int r, int rt) { if( l == r ) { no[rt] = ls[rt] = rs[rt] = 1; return; } int m = (l+r) >> 1; build( lson ); build( rson ); pushUp(l, r, rt); } void update(int l, int r, int rt) { if( l == r ) return; int m = (l+r) >> 1; if( x <= m ) update(lson); else update(rson); pushUp(l, r, rt); } int query(int l, int r, int rt) { // cout << l << " " << r << endl; cout << "rt: " << rt << endl; if( x <= l && r <= y ) return no[rt]; int m = (l + r) >> 1; if( y <= m ) return query(lson); // cout << "**" << endl; if( x > m ) return query(rson); int t1 = query(lson); int t2 = query(rson); int ans = max( t1, t2 ); if( a[m] < a[m+1] ) { // ans = max( ans, ls[rt<<1|1]+rs[rt<<1] ); ans=max(ans,(min(ls[rt<<1|1],y-m)+min(rs[rt<<1],m+1-x))); } return ans; } int main() { sca(t); while( t-- ) { scanf( "%d%d", &n, &mm ); for( int i = 1; i <= n; i++ ) { sca(a[i]); } build(1, n, 1); char op[5]; while( mm-- ) { scanf( "%s%d%d", op, &x, &y ); ++x; if( op[0] == 'U' ) { a[x] = y; update(1, n, 1); } else { ++y; printf( "%d\n", query(1, n, 1) ); } } } return 0; }
思考: 线段树是个大坑啊....自己挖的坑自己填吧.......看看剑指offer啥的吧....下午又是水课
posted on 2017-09-04 12:07 FriskyPuppy 阅读(155) 评论(0) 编辑 收藏 举报