线段树模板
Posted linhaitai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树模板相关的知识,希望对你有一定的参考价值。
模板:
成段更新:
#include <cstdio> #include <algorithm> using namespace std; #define LL long long #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 111111; LL addv[maxn<<2]; LL sumv[maxn<<2]; //int maxv[maxn<<2]; void PushUp(int rt) { // maxv[rt] = max(maxv[rt<<1], maxv[rt<<1|1]); sumv[rt] = sumv[rt<<1] + sumv[rt<<1|1]; } void PushDown(int rt,int m) { if (addv[rt]) { addv[rt<<1] += addv[rt]; addv[rt<<1|1] += addv[rt]; sumv[rt<<1] += addv[rt] * (m - (m >> 1)); sumv[rt<<1|1] += addv[rt] * (m >> 1); // maxv[rt<<1] += addv[rt]; // maxv[rt<<1|1] += addv[rt]; addv[rt] = 0; } } void build(int l,int r,int rt) { addv[rt] = 0; if (l == r) { scanf("%I64d",&sumv[rt]); //scanf("%d", &maxv[rt]); return ; } int m = (l + r) >> 1; build(lson); build(rson); PushUp(rt); } void update(int L,int R,int c,int l,int r,int rt) { if (L <= l && r <= R) { addv[rt] += c; sumv[rt] += (LL)c * (r - l + 1); //maxv[rt] += c return ; } PushDown(rt , r - l + 1); int m = (l + r) >> 1; if (L <= m) update(L , R , c , lson); if (m < R) update(L , R , c , rson); PushUp(rt); } LL query(int L,int R,int l,int r,int rt) { if (L <= l && r <= R) { //return maxv[rt]; return sumv[rt]; } PushDown(rt , r - l + 1); int m = (l + r) >> 1; LL ret = 0; if (L <= m) ret += query(L, R, lson); //ret = max(ret, query(L , R , lson)); if (m < R) ret += query(L, R, rson); //ret = max(ret, query(L , R , rson)); return ret; } int main() { int N , Q; scanf("%d%d",&N,&Q); build(1 , N , 1); while (Q --) { char op[2]; int a , b , c; scanf("%s",op); if (op[0] == ‘Q‘) { scanf("%d%d",&a,&b); printf("%I64d ",query(a , b , 1 , N , 1)); } else { scanf("%d%d%d",&a,&b,&c); update(a , b , c , 1 , N , 1); } } return 0; }
成段置值:
#include <cstdio> #include <algorithm> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 111111; int h , w , n; int col[maxn<<2]; int sum[maxn<<2]; void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void PushDown(int rt,int m) { if (col[rt]) { col[rt<<1] = col[rt<<1|1] = col[rt]; sum[rt<<1] = (m - (m >> 1)) * col[rt]; sum[rt<<1|1] = (m >> 1) * col[rt]; col[rt] = 0; } } void build(int l,int r,int rt) { col[rt] = 0; sum[rt] = 1; if (l == r) return ; int m = (l + r) >> 1; build(lson); build(rson); PushUp(rt); } int query(int L,int R,int l,int r,int rt) {//求和写法,参数信息=>(问询区间左端点,问询区间右端点,总区间左端点,总区间右端点,根节点编号) if (L <= l && r <= R) { return sumv[rt]; } int m = l + ((r - l)>>1); int ret = 0; if (L <= m) ret += query(L , R , lson); if (R > m) ret += query(L , R , rson); return ret; } void update(int L,int R,int c,int l,int r,int rt) { if (L <= l && r <= R) { col[rt] = c; sum[rt] = c * (r - l + 1); return ; } PushDown(rt , r - l + 1); int m = (l + r) >> 1; if (L <= m) update(L , R , c , lson); if (R > m) update(L , R , c , rson); PushUp(rt); } int main() { int T , n , m; scanf("%d",&T); for (int cas = 1 ; cas <= T ; cas ++) { scanf("%d%d",&n,&m); build(1 , n , 1); while (m --) { int a , b , c; scanf("%d%d%d",&a,&b,&c); update(a , b , c , 1 , n , 1); } printf("Case %d: The total value of the hook is %d. ",cas , sum[1]); } return 0; }
单点更新:
/* 说明: 此模板支持对于线段的单点加减操作更新、区间最值or和的查询 下面主要以求和操作为例,注释部分为求最值功能,根据自己的 需求适当修改模板 验证题目:HDU 1166 敌兵布阵 (以下代码也是解决此题的代码) */ #include <cstdio> #include <algorithm> #include <string.h> using namespace std; #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 const int maxn = 50005;//maxn = 线段的最大长度 则=> maxn<<2 = 线段树可能的最多结点 //int maxv[maxn<<2];//保存最大值 //int minv[maxn<<2];//保存最小值 int sumv[maxn<<2];//保存区间和 void PushUP(int rt) { //maxv[rt] = max(maxv[rt<<1] , maxv[rt<<1|1]); //minv[rt] = min(minv[rt<<1], minv[rt<<1|1]); sumv[rt] = sumv[rt<<1] + sumv[rt<<1|1]; } void build(int l,int r,int rt) {//设置初始值 if (l == r) { // scanf("%d",&maxv[rt]); // scanf("%d", &minv[rt]); scanf("%d", &sumv[rt]); return ; } int m = l + ((r - l)>>1); build(lson); build(rson); PushUP(rt); } void update(int p,int sc,int l,int r,int rt) {//单点更新,参数(更新点,更新值,总区间左端点,总区间右端点,根节点编号) if (l == r) { //maxv[rt] = sc; //minv[rt] = sc; sumv[rt] += sc; return ; } int m = l + ((r - l)>>1); if (p <= m) update(p , sc , lson); else update(p , sc , rson); PushUP(rt); } // int query(int L,int R,int l,int r,int rt) {//查询最大值的写法、最小值同理、求和区间写法在下面 // if (L <= l && r <= R) { // return maxv[rt]; // } // int m = (l + r) >> 1; // int ret = 0; // if (L <= m) ret = max(ret , query(L , R , lson)); // if (R > m) ret = max(ret , query(L , R , rson)); // return ret; // } int query(int L,int R,int l,int r,int rt) {//求和写法,参数信息=>(问询区间左端点,问询区间右端点,总区间左端点,总区间右端点,根节点编号) if (L <= l && r <= R) { return sumv[rt]; } int m = l + ((r - l)>>1); int ret = 0; if (L <= m) ret += query(L , R , lson); if (R > m) ret += query(L , R , rson); return ret; } int main(void) { int nCase; scanf("%d", &nCase); for(int t = 1; t <= nCase; t++){ memset(sumv, 0, sizeof(sumv)); int len; scanf("%d", &len); build(1, len, 1); char s[20]; printf("Case %d: ", t); while(~scanf("%s", s) && s[0] != ‘E‘){//s != ‘End‘ if(s[0] == ‘Q‘){//s = Query int L, R; scanf("%d %d", &L, &R); printf("%d ", query(L, R, 1, len, 1)); } else if(s[0] == ‘S‘){//减操作 int point, val; scanf("%d%d", &point, &val); update(point, -val, 1, len, 1); } else if(s[0] == ‘A‘){//加操作 int point, val; scanf("%d%d", &point, &val); update(point, val, 1, len, 1); } } } return 0; }
以上是关于线段树模板的主要内容,如果未能解决你的问题,请参考以下文章