bzoj3212: Pku3468 A Simple Problem with Integers(線段樹)

Hanks_o發表於2018-03-24

題目傳送門

解法:
線段樹改段求段。
打懶標記。

程式碼實現:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node {int l,r,lc,rc;ll ss,c,lazy;}tr[210000];int len;
void bt(int l,int r) {
    int now=++len;
    tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1;tr[now].c=tr[now].lazy=0ll;tr[now].ss=r-l+1;
    if(l<r) {
        int mid=(l+r)/2;tr[now].lc=len+1;bt(l,mid);tr[now].rc=len+1;bt(mid+1,r);
    }
}
void update(int now) {
    int lc=tr[now].lc,rc=tr[now].rc;
    if(lc==-1)return ;
    tr[lc].c+=tr[lc].ss*tr[now].lazy;tr[rc].c+=tr[rc].ss*tr[now].lazy;
    tr[lc].lazy+=tr[now].lazy;tr[rc].lazy+=tr[now].lazy;tr[now].lazy=0ll;
}
void change(int now,int l,int r,ll k) {
    if(tr[now].lazy)update(now);
    if(tr[now].l==l&&tr[now].r==r) {tr[now].c+=tr[now].ss*k;tr[now].lazy+=k;return ;}
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)change(lc,l,r,k);else if(l>mid)change(rc,l,r,k);
    else {change(lc,l,mid,k);change(rc,mid+1,r,k);}
    tr[now].c=tr[lc].c+tr[rc].c;
}
ll find_sum(int now,int l,int r) {
    if(tr[now].lazy)update(now);
    if(tr[now].l==l&&tr[now].r==r)return tr[now].c;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)return find_sum(lc,l,r);else if(l>mid)return find_sum(rc,l,r);
    else return find_sum(lc,l,mid)+find_sum(rc,mid+1,r);
}
char s[5];
int main() {
    int n,q;scanf("%d%d",&n,&q);len=0;bt(1,n);
    for(int i=1;i<=n;i++) {ll x;scanf("%lld",&x);change(1,i,i,x);}
    for(int i=1;i<=q;i++) {
        scanf("%s",s+1);int x,y;scanf("%d%d",&x,&y);if(x>y)swap(x,y);
        if(s[1]=='Q') printf("%lld\n",find_sum(1,x,y));
        else {ll k;scanf("%lld",&k);change(1,x,y,k);}
    }
    return 0;
}

相關文章