線段樹-題解

nyoj 1068

題目鏈接  http://acm.nyist.net/JudgeOnline/problem.php?pid=1068

題目意思; 典型的線段樹,插線問線.不過多了一個,

A 操作某一個區間一個數整體加上一個數;

S 操作查詢某一個區間的總和,

Q 操作,查詢這個區間有多少個奇數.

下面是 線段樹延遲更新,奇數的個數更新時注意 

如果變化的是奇數,那麼  : 現在區間奇數個數=區間長度-原本區間的奇數個數.

下面 延遲更新  模板題目.如果對模板不太理解,請看這個博 或者看代碼註釋

延遲更新大致思想: 每一次數據更新,  [a,b] 區間,則只需要更新到他們的子區間且  滿足各個子區間無交集 且 並集爲區間 [a,b];每次更新,都更新到這些子區間停止,遞歸歸的時候再更新上面的值. 查詢的時候mark,標記的是上次更新到這裏停止了,如果要往下走,標記下沉,並計算左右兒子.


#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<deque>
#include<stack>
#include<string>
#include<vector>
#include<iostream>
#include<algorithm>
#include<stdlib.h>
#include<time.h>

using namespace std;
typedef long long LL;
const int INF=2e9+1e8;
const int MOD=1e9+7;
const int MAXSIZE=1e6+5;
const double eps=0.0000000001;
void fre()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}
#define memst(a,b) memset(a,b,sizeof(a))
#define fr(i,a,n) for(int i=a;i<n;i++)

struct Node
{
    LL odd,sum,mark;
    LL l,r;
} Tree[10005*4];
LL arr[MAXSIZE];
void build(LL l,LL r,LL pos) //建樹過程,遞歸建樹
{
    Tree[pos].mark=0;//初始化標記變量
    Tree[pos].l=l,Tree[pos].r=r;
    LL mid=(l+r)>>1ll;
    if(l==r)
    {
        Tree[pos].sum=arr[l];
        if(arr[l]&1ll) Tree[pos].odd=1ll;
        else Tree[pos].odd=0;
        return ;
    }
    build(l,mid,pos<<1ll);
    build(mid+1ll,r,pos<<1ll|1ll);
    //上面是遞的過程,下面是歸併且求和;
    Tree[pos].sum=Tree[pos<<1ll].sum+Tree[pos<<1ll|1ll].sum;
    Tree[pos].odd=Tree[pos<<1ll].odd+Tree[pos<<1ll|1ll].odd;
    return ;
}
/**   pushdown 函數
將本節點的左右孩子節點的標記變量加上自己節點的標記值,
且把計算結果(通常是求和)並把自己的標記值清空
*/
void pushdown(LL pos)
{
    if(Tree[pos].mark)
    {
        Tree[pos<<1ll].mark+=Tree[pos].mark,Tree[pos<<1ll|1ll].mark+=Tree[pos].mark;
        Tree[pos<<1ll].sum+=(Tree[pos<<1ll].r-Tree[pos<<1ll].l+1ll)*Tree[pos].mark;
        Tree[pos<<1ll|1ll].sum+=(Tree[pos<<1ll|1ll].r-Tree[pos<<1ll|1ll].l+1ll)*Tree[pos].mark;
        if(Tree[pos].mark&1ll)
        {
            Tree[pos<<1ll].odd=(Tree[pos<<1ll].r-Tree[pos<<1ll].l+1ll)-Tree[pos<<1ll].odd;
            Tree[pos<<1ll|1ll].odd=(Tree[pos<<1ll|1ll].r-Tree[pos<<1ll|1ll].l+1ll)-Tree[pos<<1ll|1ll].odd;
        }
        Tree[pos].mark=0;
    }
}
/** update 函數
插線函數,遞歸開始;
如果找到子區間則,更新當前節點,因爲只不需要更新到葉子節點,
所以,計算當前值,把當前節點的標記變量 加上 k,停止遞歸;

否則接着遞歸下去,每次需要下沉標記,並計算;
--> 遞歸
合併左右孩子節點的值,
*/
void update(LL l,LL r,LL pos,LL k)
{
    LL mid=(Tree[pos].l+Tree[pos].r)>>1ll;
    if(Tree[pos].l==l&&Tree[pos].r==r) //如果更新到子區間
    {
        Tree[pos].mark+=k;//標記變量自加
        //每次更新都活到這裏,所以計算的時候是 k ,不是 mark
        Tree[pos].sum+=(Tree[pos].r-Tree[pos].l+1ll)*k; //
        if(k&1ll) Tree[pos].odd=(Tree[pos].r-Tree[pos].l+1ll)-Tree[pos].odd;
        return ;
    }
    pushdown(pos);
    if(mid<l) update(l,r,pos<<1ll|1ll,k);
    else if(r<=mid)update(l,r,pos<<1ll,k);
    else
    {
        update(l,mid,pos<<1ll,k);
        update(mid+1ll,r,pos<<1ll|1ll,k);
    }
    Tree[pos].sum=Tree[pos<<1ll].sum+Tree[pos<<1ll|1ll].sum;
    Tree[pos].odd=Tree[pos<<1ll].odd+Tree[pos<<1ll|1ll].odd;
}
void Debug(LL pos)
{
    printf("l=%d r=%d sum=%d odd=%d mark=%d\n",Tree[pos].l,Tree[pos].r,Tree[pos].sum,Tree[pos].odd,Tree[pos].mark);
    if(Tree[pos].l==Tree[pos].r) return ;
    Debug(pos<<1ll);
    Debug(pos<<1ll|1ll);
}
/**  query 函數-返回答案
只要查詢,並且標記下沉,計算;
*/
LL query(LL l,LL r,LL pos,char opt)
{
    LL mid=(Tree[pos].l+Tree[pos].r)>>1ll;
    if(Tree[pos].l==l&&Tree[pos].r==r)
    {
        if(opt=='S') return Tree[pos].sum;
        else return Tree[pos].odd;
    }
    pushdown(pos);
    if(mid<l) return query(l,r,pos<<1ll|1ll,opt);
    else if(r<=mid) return query(l,r,pos<<1ll,opt);
    else return query(l,mid,pos<<1ll,opt)+query(mid+1ll,r,pos<<1ll|1ll,opt);
}
int main()
{
    LL n,m;
    while(scanf("%lld%lld",&n,&m)+1ll)
    {
        LL a,b,c;
        for(LL i=1ll; i<=n; i++) scanf("%lld",&arr[i]);
        build(1ll,n,1ll);
        for(LL i=0; i<m; i++)
        {
            char opt[3];
            scanf("%s",opt);
            if(opt[0]=='A')
            {
                scanf("%lld%lld%lld",&a,&b,&c);
                update(a,b,1ll,c);
                //  Debug(1ll);
            }
            else
            {
                scanf("%lld%lld",&a,&b);
                printf("%lld\n",query(a,b,1ll,opt[0]));
            }
        }
    }
    return 0;
}

/**************************************************/
/**             Copyright Notice                 **/
/**  writer: wurong                              **/
/**  school: nyist                               **/
/**  blog  : http://blog.csdn.net/wr_technology  **/
/**************************************************/


發佈了100 篇原創文章 · 獲贊 46 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章