题目背景
小新经常陪小白去公园玩,也就是所谓的遛狗啦…
题目描述
在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。
一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第aa个和第bb个公园之间(包括aa、bb两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。
那么,就请你来帮小白选择公园吧。
输入格式
第一行,两个整数NN和MM,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。
接下来NN行,每行一个整数,依次给出小白 开始时对公园的打分。
接下来MM行,每行三个整数。第一个整数KK,11或22。
- K=1K=1表示,小新要带小白出去玩,接下来的两个整数aa和bb给出了选择公园的范围(1≤a,b≤N1≤a,b≤N)。测试数据可能会出现a>ba>b的情况,需要进行交换;
- K=2K=2表示,小白改变了对某个公园的打分,接下来的两个整数pp和ss,表示小白对第pp个公园的打分变成了ss(1≤p≤N1≤p≤N)。
其中,1≤N≤500 0001≤N≤500000,1≤M≤100 0001≤M≤100000,所有打分都是绝对值不超过10001000的整数。
输出格式
小白每出去玩一次,都对应输出一行,只包含一个整数,表示小白可以选出的公园得分和的最大值。
输入输出样例
输入 #1
5 3 1 2 -3 4 5 1 2 3 2 2 -1 1 2 3
输出 #1
2 -1
思路:不得不说这个题是一个好题,而且加深了我对线段树的理解,让我知道了线段树还能这么用。
其实这个题没想象中的难,个人感觉蓝题左右,难度不到紫题,洛谷评分虚高了一点。我这里用了一个技巧,用L表示区间左端点严格为线段树节点区间左端点的子序列最大值,R同理
s则是区间左右端点不加以限制的最大值(也就是题目要的答案)。显然线段树在合并信息的时候,L的值为:max{左子节点的L,左子节点sum加上右子节点的L},R同理,s则为
max{左子节点s,右子节点s,左子节点R与右子节点L的和}(想想为什么),然后按正常的线段树操作做即可。
没想象中的难。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N = 5e5 + 5; 7 struct seg{ 8 int l, r; 9 int sum, L, R, s; 10 }tr[N << 2]; 11 int n, m, num[N]; 12 #define ls p << 1 13 #define rs p << 1|1 14 #define inf 2e9 15 void update(int p) 16 { 17 tr[p].sum = tr[ls].sum + tr[rs].sum; 18 tr[p].L = max(tr[ls].L, tr[ls].sum + tr[rs].L); 19 tr[p].R = max(tr[rs].R, tr[rs].sum + tr[ls].R); 20 tr[p].s = max(max(tr[ls].s, tr[rs].s), tr[ls].R + tr[rs].L); 21 } 22 void build(int p, int l, int r) 23 { 24 tr[p].l = l; 25 tr[p].r = r; 26 if(l == r) 27 { 28 tr[p].sum = num[l]; 29 tr[p].L = num[l]; 30 tr[p].R = num[l]; 31 tr[p].s = num[l]; 32 return; 33 } 34 int mid = l + r >> 1; 35 build(ls, l, mid); 36 build(rs, mid + 1, r); 37 update(p); 38 } 39 void modify_set(int p, int pos, int v) 40 { 41 if(tr[p].l == tr[p].r) 42 { 43 tr[p].sum = v; 44 tr[p].L = v; 45 tr[p].R = v; 46 tr[p].s = v; 47 return; 48 } 49 int mid = tr[p].l + tr[p].r >> 1; 50 if(pos <= mid) modify_set(ls, pos, v); 51 else modify_set(rs, pos, v); 52 update(p); 53 } 54 seg query(int p, int l, int r) 55 { 56 if(l <= tr[p].l && r >= tr[p].r) 57 { 58 return tr[p]; 59 } 60 int mid = tr[p].l + tr[p].r >> 1; 61 seg lz = (seg){0, 0, 0, -inf, -inf, -inf}; 62 seg rz = (seg){0, 0, 0, -inf, -inf, -inf}; 63 seg ret; 64 if(l <= mid) lz = query(ls, l, r); 65 if(r > mid) rz = query(rs, l, r); 66 ret.sum = lz.sum + rz.sum; 67 ret.L = max(lz.L, lz.sum + rz.L); 68 ret.R = max(rz.R, rz.sum + lz.R); 69 ret.s = max(max(lz.s, rz.s), lz.R + rz.L); 70 return ret; 71 } 72 int main() 73 { 74 scanf("%d%d", &n, &m); 75 for(int i = 1; i <= n; i ++) 76 scanf("%d", &num[i]); 77 build(1, 1, n); 78 int op, a, b; 79 while(m --) 80 { 81 scanf("%d%d%d", &op, &a, &b); 82 if(op == 1) 83 { 84 if(a > b) swap(a, b); 85 printf("%d ", query(1, a, b).s); 86 } 87 else modify_set(1, a, b); 88 } 89 return 0; 90 }