codevs 4927 线段树练习5
题目描述 Description
有n个数和5种操作
add a b c:把区间[a,b]内的所有数都增加c
set a b c:把区间[a,b]内的所有数都设为c
sum a b:查询区间[a,b]的区间和
max a b:查询区间[a,b]的最大值
min a b:查询区间[a,b]的最小值
输入描述 Input Description
第一行两个整数n,m,第二行n个整数表示这n个数的初始值
接下来m行操作,同题目描述
输出描述
Output Description
对于所有的sum、max、min询问,一行输出一个答案
样例输入 Sample Input
10 6
3 9 2 8 1 7 5 0 4 6
add 4 9 4
set 2 6 2
add 3 8 2
sum 2 10
max 1 7
min 3 6
样例输出 Sample Output
49
11
4
数据范围及提示 Data Size & Hint
10%:1<n,m<=10
30%:1<n,m<=10000
100%:1<n,m<=100000
保证中间结果在long long(C/C++)、int64(pascal)范围内
考察算法:线段树双重标记
思路:线段树区间加法和区间赋值
先赋值,后加法(赋值后,之前的加法失效)
注意:有将区间内的数都赋为0的情况
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define N 100001 #define LL long long using namespace std; int n, m, x, y; LL z; string s; bool sign; struct nond { int ll, rr; LL flag1, flag2, sum; LL minn, maxn; }tree[4*N]; void up(int now) { tree[now].sum = tree[now*2].sum+tree[now*2+1].sum; tree[now].maxn = max(tree[now*2].maxn, tree[now*2+1].maxn); tree[now].minn = min(tree[now*2].minn, tree[now*2+1].minn); } void down(int now) { if(tree[now].flag2!=-1) { tree[now*2].flag1 = tree[now*2+1].flag1 = 0; tree[now*2].flag2 = tree[now].flag2; tree[now*2+1].flag2 = tree[now].flag2; tree[now*2].sum = (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag2; tree[now*2+1].sum = (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag2; tree[now*2].maxn = tree[now].flag2; tree[now*2+1].maxn = tree[now].flag2; tree[now*2].minn = tree[now].flag2; tree[now*2+1].minn = tree[now].flag2; tree[now].flag2 = -1; } if(tree[now].flag1) { tree[now*2].flag1 += tree[now].flag1; tree[now*2+1].flag1 += tree[now].flag1; tree[now*2].sum += (tree[now*2].rr-tree[now*2].ll+1) * tree[now].flag1; tree[now*2+1].sum += (tree[now*2+1].rr-tree[now*2+1].ll+1) * tree[now].flag1; tree[now*2].maxn += tree[now].flag1; tree[now*2+1].maxn += tree[now].flag1; tree[now*2].minn += tree[now].flag1; tree[now*2+1].minn += tree[now].flag1; tree[now].flag1 = 0; } return ; } void build(int now, int l, int r) { tree[now].ll = l; tree[now].rr = r; tree[now].flag1 = 0; tree[now].flag2 = -1; if(l == r) { scanf("%lld", &tree[now].sum); tree[now].maxn = tree[now].sum; tree[now].minn = tree[now].sum; return ; } int mid = (l+r) / 2; build(now*2, l, mid); build(now*2+1, mid+1, r); up(now); } void add(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) { tree[now].flag1 += z; tree[now].sum += (tree[now].rr-tree[now].ll+1) * z; tree[now].maxn += z; tree[now].minn += z; return ; } if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) add(now*2, l, mid), add(now*2+1, mid+1, r); else if(r<=mid) add(now*2, l, r); else add(now*2+1, l, r); up(now); } void set(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) { tree[now].flag2 = z; tree[now].flag1 = 0; tree[now].sum = (tree[now].rr-tree[now].ll+1) * z; tree[now].maxn = tree[now].minn = z; return ; } if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) set(now*2, l, mid), set(now*2+1, mid+1, r); else if(r<=mid) set(now*2, l, r); else set(now*2+1, l, r); up(now); } LL query(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) return tree[now].sum; if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) return query(now*2, l, mid) + query(now*2+1, mid+1, r); else if(r<=mid) return query(now*2, l, r); else return query(now*2+1, l, r); } LL little(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) return tree[now].minn; if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) return min(little(now*2, l, mid), little(now*2+1, mid+1, r)); else if(r<=mid) return little(now*2, l, r); else return little(now*2+1, l, r); } LL large(int now, int l, int r) { if(tree[now].ll==l && tree[now].rr==r) return tree[now].maxn; if(tree[now].flag2!=-1 || tree[now].flag1) down(now); int mid = (tree[now].ll+tree[now].rr) / 2; if(l<=mid && mid<r) return max(large(now*2, l, mid), large(now*2+1, mid+1, r)); else if(r<=mid) return large(now*2, l, r); else return large(now*2+1, l, r); } int main() { scanf("%d%d", &n, &m); build(1, 1, n); for(int i = 1; i <= m; i++) { cin >> s; if(s[1] == 'd') { scanf("%d%d%lld", &x, &y, &z); add(1, x, y); continue; } if(s[1] == 'e') { scanf("%d%d%lld", &x, &y, &z); set(1, x, y); continue; } if(s[1] == 'u') { scanf("%d%d", &x, &y); printf("%lld\n", query(1, x, y)); continue; } if(s[1] == 'i') { scanf("%d%d", &x, &y); printf("%lld\n", little(1, x, y)); continue; } if(s[1] == 'a') { scanf("%d%d", &x, &y); printf("%lld\n", large(1, x, y)); continue; } } return 0; }