POJ_3468 A Simple Problem with Integers(线段树区间修改+附线段树模板)

题目链接

题目大意

中文题目

解决

  1. 线段树区间修改+求和查询的裸题
  2. 直接附上代码^_^
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <complex>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define E 1e-6
#define INF 0x3f3f3f3f
#pragma comment(linker, "/STACK:1024000000,1024000000")
void open(){freopen("data.txt","r",stdin);}
void out(){freopen("out.txt","w",stdout);}
const int maxn = 1e5+5;
const int MOD = 1e9 + 7;

int a[maxn];
ll st[maxn<<2],add[maxn<<2];

void build(int o,int l,int r)
{
    if(l==r)    st[o] = a[l];
    else{
        int m = (l+r)>>1;
        build(o<<1,l,m);
        build((o<<1)|1,m+1,r);
        st[o] = st[o<<1]+st[(o<<1)|1];
    }
}

void pushup(int o)
{
    st[o] = st[o<<1]+st[(o<<1)|1];
}

void pushdown(int o,int l,int r)
{
    if(add[o]){
        add[o<<1]+=add[o];
        add[(o<<1)|1]+=add[o];
        int m = (l+r)>>1;
        st[o<<1]+=add[o]*(m-l+1);
        st[(o<<1)|1]+=add[o]*(r-m);
        add[o] = 0;
    }
}

void update(int o,int l,int r,int al,int ar,int addv)
{
    if(al<=l&&ar>=r){
        add[o]+=addv;
        st[o]+=addv*(r-l+1);
    }
    else{
        pushdown(o,l,r);
        int m = (l+r)>>1;
        if(al<=m)   update(o<<1,l,m,al,ar,addv);
        if(ar>=m+1) update((o<<1)|1,m+1,r,al,ar,addv);
        pushup(o);
    }
}

ll query(int o,int l,int r,int ql,int qr)
{
    if(ql<=l && qr>=r)  return st[o];
    pushdown(o,l,r);
    int m = (l+r)>>1;
    ll ans = 0;
    if(ql<=m)   ans+=query(o<<1,l,m,ql,qr);
    if(qr>=m+1) ans+=query((o<<1)|1,m+1,r,ql,qr);
    return ans;
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    rep(i,1,n+1) scanf("%d",&a[i]);
    build(1,1,n);

    rep(i,0,m){
        char c;
        int u,v,w;
        getchar();
        scanf("%c",&c);
        if(c=='Q'){
            scanf("%d%d",&u,&v);
            printf("%lld\n",query(1,1,n,u,v));
        }
        else{
            scanf("%d%d%d",&u,&v,&w);
            update(1,1,n,u,v,w);
        }
    }
    return 0;
}

个人总结的线段树模板

int a[maxn] , st[maxn<<2] , change[maxn<<2] , add[maxn<<2];
//  st数组用于保存信息,可以是区间最大值、区间最小值、区间和等
void build(int o,int l,int r)
{
    if(l==r) st[o] = a[l];
    else{
        int m = (l+r)>>1;
        build(o<<1,l,m);
        build((o<<1)|1,m+1,r);
        st[o] = st[o<<1]+st[(o<<1)|1];
    //  st[o] = max(st[o<<1] , st[(o<<1)|1]);
    //  st[o] = min(st[o<<1] , st[(o<<1)|1]);
    }
}
/*  ——————————单点更新——————————
void update(int o,int l,int r,int ind,int ans)
{
    if(l==r)    st[o] = ans;
    else{
        int m = (l+r)>>1;
        if(ind<=m)  update(o<<1,l,m,ind,ans);
        else        update((o<<1)|1,m+1,r,ind,ans);
        st[o] = st[o<<1]+st[(o<<1)|1];
    //  st[o] = max(st[o<<1] , st[(o<<1)|1]);
    //  st[o] = min(st[o<<1] , st[(o<<1)|1]);
    }
}

int query(int o,int l,int r,int ql,int qr)
{
    if(ql>r||qr<l)      return -1;           //返回一个对查询结果无关的量
    if(ql<=1&&qr>=r)    return st[o];
    int m = (l+r)>>1;
    int p1 = query(o<<1,l,m,ql,qr) , p2 = query((o<<1)|1,m+1,r,ql,qr);
    return max(p1,p2);
}
    ————————————END————————     */

//  ——————以下区间修改——————

void pushup(int o){
    st[o] = st[o<<1] + st[(o<<1)|1];
//  st[o] = max(st[o<<1] , st[(o<<1)|1]);
//  st[o] = min(st[o<<1] , st[(o<<1)|1]);
}

//  ——————————区间加值——————————
void pushdown(int o,int l,int r)        //pushdown_区间加值
{
    if(add[o]){                         //当前节点上有待更新值
        add[o<<1]+=add[o];              //传递至左子节点
        add[(o<<1)|1]+=add[o];          //传递至右子节点
        int m = (l+r)>>1;
        st[o<<1]+=add[o]*(m-l+1);
        st[(o<<1)|1]+=add[o]*(r-m);
        add[o] = 0;                     //父亲节点更新信息删除
    }
}
//  用于区间加值,配合add数组使用
void update(int o,int l,int r,int al,int ar,int addv)
{
    if(al<=l && ar>=r){                 //当前区间被覆盖
        add[o]+=addv;
        st[o]+=addv*(r-l+1);
    }
    else{
        pushdown(o,l,r);                //当前节点更新信息传递至下一层
        int m = (l+r)>>1;
        if(al<=m)   update(o<<1,l,m,al,ar,addv);
        if(ar>=m+1) update((o<<1)|1,m+1,r,al,ar,addv);
        pushup(o);
    }
}
//  ——————————END——————————————

/*  ————————区间改值——————————
void pushdown(int o,int l,int r)        //pushdown_区间改值
{
    if(change[o]){
        int s = change[o];
        change[o<<1] = s;
        change[(o<<1)|1] = s;
        int m = (l+r)>>1;
        st[o<<1] = (m-l+1)*s;
        st[(o<<1)|1] = (r-m)*s;
        change[o] = 0;
    }
}

//  用于区间改值,配合change数组使用
void update(int o,int l,int r,int sl,int sr,int s)
{
    if(sl<=l && sr>=r){
        change[o] = s;
        st[o] = (r-l+1)*s;
    }
    else{
        pushdown(o,l,r);
        int m = (l+r)>>1;
        if(sl<=m)   update(o<<1,l,m,sl,sr,s);
        if(sr>=m+1) update((o<<1)|1,m+1,r,sl,sr,s);
        pushup(o);
    }
}
    ——————————END————————————   */

int query(int o,int l,int r,int ql,int qr)          //区间修改问题查询通用
{
    if(ql<=l && qr>=r) return st[o];                //当前节点覆盖区间即为所需查询区间
    pushdown(o,l,r);                                //将待查询节点的更新信息传递给子节点
    int m = (l+r)>>1;
    ll ans = 0;
    if(ql<=m)   ans+=query(o<<1,l,m,ql,qr);         //查询区间与当前节点左子节点有交集,结果加上左子节点查询结果
    if(qr>=m+1) ans+=query((o<<1)|1,m+1,r,ql,qr);   //查询区间与当前节点右子节点有交集,结果加上右子节点查询结果
    return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值