poj 3468 A Simple Problem with Integers 線段樹 區間更新求和

線段樹第二天,下午由於做了多校的第一場virtual judge,所以直到晚上纔有時間來搞這道題

除了早上做的那個區間染色的問題,這個問題應該也是個入門題,當然由於鄙人智商是硬傷,沒太反應明白,查瞭解題報告,再加上自己的一些嘗試,最終僥倖AC了,下面說說思路:

首先,更新區間的時候不可能更新區間裏的每一個點,這樣複雜度太高

因此,在update的時候,找到對應的區間之後,直接給該區間存儲一個變化值,我放在了add數組中,同時,對每個節點還維護了一個和,存在sum數組中,表示區間內所有數的和。push_up函數就是對父節點就子節點的和,push_down是重點,因爲更新是隻更新到區間的,那麼當下一次更新是對這個已經更新過的區間的子區間進行更新時,必須將他的變化量傳到子節點中去,舉個例子,假設我第一次對(2,6)區間加2,第二次對(3,4)區間加1,此時,在第一次操作後,只有(2,6)對應的add有值,其子區間對應的add都是爲0,所以,第二次去更新的時候,先把這個值傳遞到子區間中去,然後再向下找,這是爲了保證整棵樹維護的信息的正確性,而在父節點向子節點push_down的時候,可以對子節點的sum進行一下更新,以方便查找,具體的看push_down函數就可以體會。在對該節點的子節點插入後,得更新該節點的信息,即push_up一下

下面說查詢,查詢和update其實差不度,如果找到區間了,就直接返回區間的和,否則,還是得先push_down一下,再對子節點進行遞歸

以下是代碼:

#include <cstdio>
#include <cstring>
const int MAX = 100010;
long long sum[MAX<<2];
long long add[MAX<<2];
void push_up(int rt)
{
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void push_down(int l,int r,int rt)
{
    if(add[rt])
    {
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        int mid = l+r>>1;
        sum[rt<<1] += (mid-l+1)*add[rt];
        sum[rt<<1|1] += (r-mid)*add[rt];
        add[rt] = 0;
    }
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        scanf("%lld",&sum[rt]);
        return;
    }
    int mid = r+l>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    push_up(rt);
}
void update(long long p,int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        add[rt]+=p;
        sum[rt]+=p*(r-l+1);
        return;
    }
    int mid = r+l>>1;
    push_down(l,r,rt);
    if(L<=mid) update(p,L,R,l,mid,rt<<1);
    if(R>mid) update(p,L,R,mid+1,r,rt<<1|1);
    push_up(rt);
}
long long query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    return sum[rt];
    int mid = r+l>>1;
    long long ans = 0;
    push_down(l,r,rt);
    if(L<=mid) ans+=query(L,R,l,mid,rt<<1);
    if(R>mid) ans+=query(L,R,mid+1,r,rt<<1|1);
    return ans;
}
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)==2)
    {
        memset(add,0,sizeof(add));
        build(1,n,1);
        char c;
        int x,y;
        long long z;
        while(k--)
        {
            scanf(" %c",&c);
            if(c=='Q')
            {
                scanf("%d%d",&x,&y);
                printf("%lld\n",query(x,y,1,n,1));
            }
            else
            {
                scanf("%d%d%lld",&x,&y,&z);
                update(z,x,y,1,n,1);
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章