hdu 3308 LCIS 线段树

题目链接

给出n个数m个询问, 询问有两种, 一种是将第x个数改为y, 一种是询问[x, y]之间最长连续上升序列,  因为是连续的, 所以就是一个简单的区间合并问题。

用5个数组, 记录一个区间内的最长连续序列, 最长前缀, 最长后缀, 区间左端点的数是几, 右端点的数是几, 合并的时候判断左区间右端点的数是否小于右区间左端点的数。

还要注意他给出的范围[l, r]是从0开始的, 所以应该+1。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define pb(x) push_back(x)
 4 #define ll long long
 5 #define mk(x, y) make_pair(x, y)
 6 #define lson l, m, rt<<1
 7 #define mem(a) memset(a, 0, sizeof(a))
 8 #define rson m+1, r, rt<<1|1
 9 #define mem1(a) memset(a, -1, sizeof(a))
10 #define mem2(a) memset(a, 0x3f, sizeof(a))
11 #define rep(i, a, n) for(int i = a; i<n; i++)
12 #define ull unsigned long long
13 typedef pair<int, int> pll;
14 const double PI = acos(-1.0);
15 const double eps = 1e-8;
16 const int mod = 1e9+7;
17 const int inf = 1061109567;
18 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
19 const int maxn = 1e5+5;
20 int maxx[maxn<<2], pre_max[maxn<<2], suf_max[maxn<<2], lnum[maxn<<2], rnum[maxn<<2];
21 void pushUp(int rt, int m) {
22     maxx[rt] = max(maxx[rt<<1], maxx[rt<<1|1]);
23     pre_max[rt] = pre_max[rt<<1];
24     suf_max[rt] = suf_max[rt<<1|1];
25     lnum[rt] = lnum[rt<<1];
26     rnum[rt] = rnum[rt<<1|1];
27     if(rnum[rt<<1]<lnum[rt<<1|1]) {
28         maxx[rt] = max(maxx[rt], pre_max[rt<<1|1]+suf_max[rt<<1]);
29         if(pre_max[rt] == (m-(m>>1)))
30             pre_max[rt] = pre_max[rt]+pre_max[rt<<1|1];
31         if(suf_max[rt] == (m>>1))
32             suf_max[rt] = suf_max[rt<<1|1]+suf_max[rt<<1];
33     }
34 }
35 void update(int p, int val, int l, int r, int rt) {
36     if(l == r) {
37         lnum[rt] = rnum[rt] = val;
38         maxx[rt] = pre_max[rt] = suf_max[rt] = 1;
39         return ;
40     }
41     int m = l+r>>1;
42     if(p<=m)
43         update(p, val, lson);
44     else
45         update(p, val, rson);
46     pushUp(rt, r-l+1);
47 }
48 int query(int L, int R, int l, int r, int rt) {
49     if(L<=l&&R>=r) {
50         return maxx[rt];
51     }
52     int m = l+r>>1;
53     int ret1 = 0, ret2 = 0, ret3 = 0;
54     if(L<=m)
55         ret1 = query(L, R, lson);
56     if(R>m)
57         ret2 = query(L, R, rson);
58     if(L<=m&&R>m&&lnum[rt<<1|1]>rnum[rt<<1])
59         ret3 = min(m-L+1, suf_max[rt<<1])+min(R-m, pre_max[rt<<1|1]);
60     return max(ret1, max(ret2, ret3));
61 }
62 void build(int l, int r, int rt) {
63     if(l == r) {
64         scanf("%d", &rnum[rt]);
65         lnum[rt] = rnum[rt];
66         maxx[rt] = pre_max[rt] = suf_max[rt] = 1;
67         return ;
68     }
69     int m = l+r>>1;
70     build(lson);
71     build(rson);
72     pushUp(rt, r-l+1);
73 }
74 int main()
75 {
76     int t, n, m, l, r;
77     cin>>t;
78     char c[2];
79     while(t--) {
80         scanf("%d%d", &n, &m);
81         build(1, n, 1);
82         while(m--) {
83             scanf("%s%d%d", c, &l, &r);
84             if(c[0] == 'Q') {
85                 printf("%d\n", query(l+1, r+1, 1, n, 1));
86             } else {
87                 update(l+1, r, 1, n, 1);
88             }
89         }
90     }
91 }

 

转载于:https://www.cnblogs.com/yohaha/p/5041381.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值