[模板]线段树

来源:互联网 发布:佛山房产网签数据 编辑:程序博客网 时间:2024/06/06 17:15

codevs4927

1、注意代码是左闭右闭的线段树,mid在左区间内
2、打权值线段树时注意线段树右端点大于最大值

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define L(w) w << 1#define R(w) w << 1|1#define INF 1061109567typedef long long LL;using namespace std;const int MAXN = 200000 + 50;int L[MAXN << 2],R[MAXN << 2],maxn[MAXN << 2],minx[MAXN << 2],M1[MAXN << 2],M2[MAXN << 2];LL sum[MAXN << 2];int A[MAXN];void update(int w){    sum[w] = sum[L(w)] + sum[R(w)];    minx[w] = min(minx[L(w)],minx[R(w)]);    maxn[w] = max(maxn[L(w)],maxn[R(w)]);}void spread1(int w){    if(M1[w] == -1)return;    int m = M1[w];    M1[w] = -1;    minx[L(w)] = maxn[L(w)] = m;    minx[R(w)] = maxn[R(w)] = m;    sum[L(w)] = m*(R[L(w)] - L[L(w)] + 1);    sum[R(w)] = m*(R[R(w)] - L[R(w)] + 1);    M2[L(w)] = M2[R(w)] = 0;    M1[L(w)] = M1[R(w)] = m;}void spread(int w){    if(M1[w] != -1){        spread1(w);    }    int m = M2[w];    if(!m)return;    M2[w] = 0;    spread1(L(w));    spread1(R(w));    maxn[L(w)] += m;    maxn[R(w)] += m;    minx[L(w)] += m;    minx[R(w)] += m;    sum[L(w)] += m*(R[L(w)] - L[L(w)] + 1);    sum[R(w)] += m*(R[R(w)] - L[R(w)] + 1);    M2[L(w)] += m;    M2[R(w)] += m;}void build(int w,int l,int r){    L[w] = l;R[w] = r;    if(l == r){        sum[w] = minx[w] = maxn[w] = A[l];        return;    }    int mid = l + r >> 1;    build(L(w),l,mid);    build(R(w),mid + 1,r);    update(w);}void cover(int w,int l,int r,int v){    if(L[w] == l && R[w] == r){        M2[w] = 0;        M1[w] = v;        minx[w] = maxn[w] = v;        sum[w] = v*(R[w] - L[w] + 1);        return;    }    spread(w);//重置前,先下放标记     int mid = L[w] + R[w] >> 1;    if(r <= mid)cover(L(w),l,r,v);    else if(l > mid)cover(R(w),l,r,v);    else cover(L(w),l,mid,v),cover(R(w),mid + 1,r,v);    update(w);}void add(int w,int l,int r,int v){    if(L[w] == l && R[w] == r){        spread1(w);        M2[w] += v;        minx[w] += v;        maxn[w] += v;        sum[w] += v*(R[w] - L[w] + 1);        return;    }    spread(w);    int mid = L[w] + R[w] >> 1;    if(r <= mid)add(L(w),l,r,v);    else if(l > mid)add(R(w),l,r,v);    else add(L(w),l,mid,v),add(R(w),mid + 1,r,v);    update(w);}LL ask_sum(int w,int l,int r){    if(L[w] == l && R[w] == r){        return sum[w];    }    spread(w);    LL ans = 0;    int mid = L[w] + R[w] >> 1;    if(r <= mid)ans = ask_sum(L(w),l,r);    else if(l > mid)ans = ask_sum(R(w),l,r);    else ans = ask_sum(L(w),l,mid) + ask_sum(R(w),mid + 1,r);    return ans;}int ask_max(int w,int l,int r){    if(L[w] == l && R[w] == r){        return maxn[w];    }    spread(w);    int mid = L[w] + R[w] >> 1;    int ans = -INF;    if(r <= mid)ans = ask_max(L(w),l,r);    else if(l > mid)ans = ask_max(R(w),l,r);    else ans = max(ask_max(L(w),l,mid),ask_max(R(w),mid + 1,r));    return ans;}int ask_min(int w,int l,int r){    if(L[w] == l && R[w] == r){        return minx[w];    }    spread(w);    int mid = L[w] + R[w] >> 1;    int ans = INF;    if(r <= mid)ans = ask_min(L(w),l,r);    else if(l > mid)ans = ask_min(R(w),l,r);    else ans = min(ask_min(L(w),l,mid),ask_min(R(w),mid + 1,r));    return ans;}int n,m,a,b,c;string s;int main(){    memset(M1,-1,sizeof(M1));    scanf("%d%d",&n,&m);    for(int i = 1;i <= n;i ++){        scanf("%d",&A[i]);    }    build(1,1,n);    for(int i = 1;i <= m;i ++){        cin >> s;        if(s == "add"){            scanf("%d%d%d",&a,&b,&c);            add(1,a,b,c);        }        else if(s == "set"){            scanf("%d%d%d",&a,&b,&c);            cover(1,a,b,c);        }        else if(s == "sum"){            scanf("%d%d",&a,&b);            if(a > b)swap(a,b);            printf("%lld\n",ask_sum(1,a,b));        }        else if(s == "max"){            scanf("%d%d",&a,&b);            printf("%d\n",ask_max(1,a,b));        }        else if(s == "min"){            scanf("%d%d",&a,&b);            printf("%d\n",ask_min(1,a,b));        }    }    return 0;}
原创粉丝点击