模板-----------线段树

来源:互联网 发布:计算 编辑:程序博客网 时间:2024/06/05 12:42

支持区间修改及查询,适用于多次修改、多次询问;倍增RMQ算法仅支持区间查询,不支持区间修改。

练手题:

1.洛谷3352

2.codevs1080、1081、1082

#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#define ll long longusing namespace std;ll n,m,k,x,y,ans;ll a[100010];struct mc{ll l,r,num,down;}tree[400000];void build(ll l,ll r,ll num){if(l==r){tree[num].l=l;tree[num].r=r;tree[num].num=a[l];return;}tree[num].l=l;tree[num].r=r;ll mid=(l+r)>>1;ll t=num*2;build(l,mid,t);build(mid+1,r,t+1);tree[num].num=tree[t].num+tree[t+1].num;}void down(const ll num){ll l=tree[num].l;ll r=tree[num].r;if (l==r){tree[num].down=0;return;}ll t=num*2;l=tree[t].l;r=tree[t].r;tree[t].num+=(r-l+1)*tree[num].down;tree[t].down+=tree[num].down;tree[t+1].num+=(r-l+1)*tree[num].down;tree[t+1].down+=tree[num].down;tree[num].down=0;}void add(ll &x,ll &y,ll num,ll k){ll l=tree[num].l,r=tree[num].r;if (l>=x&&r<=y){tree[num].num+=(r-l+1)*k;tree[num].down+=k;return;}if (tree[num].down) down(num);ll mid=(l+r)/2;ll t=num*2;if (y<=mid) add(x,y,t,k);else if (x>mid) add(x,y,t+1,k);else {add(x,y,t,k);add(x,y,t+1,k);}tree[num].num=tree[t].num+tree[t+1].num;}void ask(ll l,ll r,ll num){if (tree[num].down!=0) down(num);if (tree[num].l>=x&&tree[num].r<=y){ans+=tree[num].num;return;}ll mid=(l+r)/2;ll t=num*2;if (y<=mid) ask(l,mid,t);else if (x>mid) ask(mid+1,r,t+1);else{ask(l,mid,t);ask(mid+1,r,t+1);}}int main(){ll n,m;cin>>n>>m;for (ll i=1;i<=n;i++)cin>>a[i];build(1,n,1);ll p;for (ll i=1;i<=m;i++){cin>>p;if (p==1){cin>>x>>y>>k;add(x,y,1,k);}else{cin>>x>>y;ans=0;ask(1,n,1);cout<<ans<<endl;}}return 0;}


0 0