码迷,mamicode.com
首页 > 其他好文 > 详细

线段树模板

时间:2017-12-24 12:54:45      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:space   自己   lap   point   操作   注释   节点   cst   保存   

成段更新:

技术分享图片
#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] = max(c, maxv[rt]);
        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\n",query(a , b , 1 , N , 1));
        } else {
            scanf("%d%d%d",&a,&b,&c);
            update(a , b , c , 1 , N , 1);
        }
    }
    return 0;
}
View Code

 

成段置值:

技术分享图片
#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.\n",cas , sum[1]);
       }
       return 0;
}
View Code

 

单点更新:

技术分享图片
/*
说明:
此模板支持对于线段的单点加减操作更新、区间最值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:\n", 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\n", 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;
}
View Code

 

融合置值和成段加减 ( 刘汝佳程序 ) :

技术分享图片
///op==1是加减更新操作
///op==其他是置值操作
///y1是查询时候的左端点
///y2是查询时候的右端点
const int maxnode = 1<<17;
int _sum, _min, _max, op, y1, y2;

struct IntervalTree {
  int sumv[maxnode], minv[maxnode], maxv[maxnode], setv[maxnode], addv[maxnode];

  void maintain(int o, int L, int R) {
    int lc = o*2, rc = o*2+1;
    if(R > L) {
      sumv[o] = sumv[lc] + sumv[rc];
      minv[o] = min(minv[lc], minv[rc]);
      maxv[o] = max(maxv[lc], maxv[rc]);
    }
    if(setv[o] >= 0) { minv[o] = maxv[o] = setv[o]; sumv[o] = setv[o] * (R-L+1); }
    if(addv[o]) { minv[o] += addv[o]; maxv[o] += addv[o]; sumv[o] += addv[o] * (R-L+1); }
  }

  void pushdown(int o) {
    int lc = o*2, rc = o*2+1;
    if(setv[o] >= 0) {
      setv[lc] = setv[rc] = setv[o];
      addv[lc] = addv[rc] = 0;
      setv[o] = -1;
    }
    if(addv[o]) {
      addv[lc] += addv[o];
      addv[rc] += addv[o];
      addv[o] = 0;
    }
  }

  void update(int o, int L, int R) {
    int lc = o*2, rc = o*2+1;
    if(y1 <= L && y2 >= R) {
      if(op == 1) addv[o] += v;
      else { setv[o] = v; addv[o] = 0; }
    } else {
      pushdown(o);
      int M = L + (R-L)/2;
      if(y1 <= M) update(lc, L, M); else maintain(lc, L, M);
      if(y2 > M) update(rc, M+1, R); else maintain(rc, M+1, R);
    }
    maintain(o, L, R);
  }

  void query(int o, int L, int R, int add) {
    if(setv[o] >= 0) {
      int v = setv[o] + add + addv[o];
      _sum += v * (min(R,y2)-max(L,y1)+1);
      _min = min(_min, v);
      _max = max(_max, v);
    } else if(y1 <= L && y2 >= R) {
      _sum += sumv[o] + add * (R-L+1);
      _min = min(_min, minv[o] + add);
      _max = max(_max, maxv[o] + add);
    } else {
      int M = L + (R-L)/2;
      if(y1 <= M) query(o*2, L, M, add + addv[o]);
      if(y2 > M) query(o*2+1, M+1, R, add + addv[o]);
    }
  }
};
View Code

 

线段树模板

标签:space   自己   lap   point   操作   注释   节点   cst   保存   

原文地址:http://www.cnblogs.com/Rubbishes/p/8097607.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!