标签:lcis date 需要 连续 单点 targe problem 右值 问题
题目链接
http://hdu.hustoj.com/showproblem.php?pid=3308
问题描述
给出n个整数,有两种操作
1)U A B:用B取代第A个数(下标从0开始)
2)Q A B:输出在[A,B]中最长连续递增子序列的长度
分析
给出一个序列,两种操作,分别是单点更新值和查询区间的最长连续递增子序列长
度,典型的线段树问题
首先考虑线段树的节点需要记录哪些值:
1)包含左端点的最长连续递增子序列长度,记作pre[]
2)包含右端点的最长连续递增子序列长度,记作suf[]
3)整个区间的最长连续递增子序列长度,记作sub[]
每次pushUp都需要自下而上更新这三个值。
注意点:
对于左连续,既可以由左儿子的左连续得来,也可能包含右儿子的左连续,这就要判断左儿子的左连续是否覆盖了整个区间,并且左儿子的最右值小于右儿子的最左值。同理对于右连续也是一样的。
对于整个区间的LCIS,可能来源于左右儿子的最值(因为可能左儿子的最右值不小于右儿子的最左值),也可能来源于两个区间的中间部分。
代码
1 #include<stdio.h> 2 const int maxn = 100010; 3 int n, m, x, y; 4 char ch[5]; 5 int val[maxn], sub[maxn * 4], pre[maxn * 4], suf[maxn * 4]; 6 7 int max(int a, int b) 8 { 9 return a > b ? a : b; 10 } 11 int min(int a, int b) 12 { 13 return a < b ? a : b; 14 } 15 16 void pushUp(int rt, int l, int r) 17 { 18 int m = (l + r) / 2; 19 20 sub[rt] = max(sub[rt * 2], sub[rt * 2 + 1]); 21 if(val[m] < val[m + 1]) 22 sub[rt] = max(sub[rt], suf[rt * 2] + pre[rt * 2 + 1]); 23 24 pre[rt] = pre[rt * 2]; 25 if(pre[rt] == m - l + 1 && val[m] < val[m + 1]) 26 pre[rt] += pre[rt * 2 + 1]; 27 28 suf[rt] = suf[rt * 2 + 1]; 29 if(suf[rt] == r - m && val[m] < val[m + 1]) 30 suf[rt] += suf[rt * 2]; 31 } 32 33 void build(int rt, int l, int r) 34 { 35 if(l == r) 36 { 37 sub[rt] = pre[rt] = suf[rt] = 1; 38 return; 39 } 40 int m = (l + r) / 2; 41 build(rt * 2, l, m); 42 build(rt * 2 + 1, m + 1, r); 43 pushUp(rt, l, r); 44 } 45 46 void update(int rt, int l, int r) 47 { 48 if(l == r) 49 return; 50 int m = (l + r) / 2; 51 if(x <= m) 52 update(rt * 2, l, m); 53 else 54 update(rt * 2 + 1, m + 1, r); 55 pushUp(rt, l, r); 56 } 57 58 int query(int rt, int l, int r) 59 { 60 if(x <= l && y >= r) 61 return sub[rt]; 62 int m = (l + r) / 2; 63 if(y <= m) 64 return query(rt * 2, l, m); 65 if(x > m) 66 return query(rt * 2 + 1, m + 1, r); 67 int ans = max(query(rt * 2, l, m), query(rt * 2 + 1, m + 1, r)); 68 if(val[m] < val[m + 1]) 69 { 70 ans = max(ans, min(suf[rt * 2], m - x + 1) + min(pre[rt * 2 + 1], y - m)); 71 } 72 return ans; 73 } 74 int main() 75 { 76 int t; 77 scanf("%d", &t); 78 while(t--) 79 { 80 scanf("%d%d", &n, &m); 81 for(int i = 1; i <= n; i++) 82 scanf("%d", &val[i]); 83 build(1, 1, n); 84 while(m--) 85 { 86 scanf("%s%d%d", ch, &x, &y); 87 x += 1; //下标:0 1 88 if(ch[0] == ‘U‘) 89 { 90 val[x] = y; 91 update(1, 1, n); 92 } 93 else if(ch[0] == ‘Q‘) 94 { 95 y += 1; 96 printf("%d\n", query(1, 1, n)); 97 } 98 } 99 } 100 return 0; 101 }
标签:lcis date 需要 连续 单点 targe problem 右值 问题
原文地址:https://www.cnblogs.com/friend-A/p/10011356.html