1. 程式人生 > >hdu 1166 敵兵佈陣 (單點更新線段樹模板)

hdu 1166 敵兵佈陣 (單點更新線段樹模板)

題目連結:哆啦A夢傳送門

題解:

 

參考連結:https://www.cnblogs.com/TenosDoIt/p/3453089.html

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn=50010;

struct node{
    int val;
}segtree[maxn*4];

int arr[maxn];

/*
 root:當前線段樹的根節點下標
 arr: 用來構造線段樹的陣列
 istart:陣列的起始位置
 iend:陣列的結束位置
 */
void build(int root,int istart,int iend)
{
    if(istart==iend){ ///葉子節點
        segtree[root].val=arr[istart];
    }
    else{

        int mid=(istart+iend)/2;
        build(root*2,istart,mid); ///遞迴構造左子樹
        build(root*2+1,mid+1,iend);///遞迴構造右子樹

         ///根據左右子樹根節點的值,更新當前根節點的值
        segtree[root].val=segtree[root*2].val+segtree[root*2+1].val;

    }
}
/*
功能:線段樹的區間查詢
root:當前線段樹的根節點下標
[nstart, nend]: 當前節點所表示的區間
[qstart, qend]: 此次查詢的區間
*/
int query(int root,int nstart,int nend,int qstart,int qend)
{
    ///查詢區間和當前節點區間沒有交集
    if(qstart>nend||qend<nstart)
        return 0;

        ///當前節點區間包含在查詢區間內
    if(qstart<=nstart&&qend>=nend)
        return segtree[root].val;

        ///分別從左右子樹查詢,返回兩者查詢結果的較小值
    int mid=(nstart+nend)/2;

    return query(root*2,nstart,mid,qstart,qend)
    +query(root*2+1,mid+1,nend,qstart,qend);
}

/*
功能:更新線段樹中某個葉子節點的值
root:當前線段樹的根節點下標
[nstart, nend]: 當前節點所表示的區間
index: 待更新節點在原始陣列arr中的下標
addVal: 更新的值(原來的值加上addVal)
*/
void updataone(int root,int nstart,int nend,int index,int addval)
{
    if(nstart==nend)
    {
        if(index==nstart) ///找到了相應的節點,更新之
        {
             segtree[root].val+=addval;
             return;
        }

    }
    int mid=(nstart+nend)/2;

    if(index<=mid) ///在左子樹中更新
        updataone(root*2,nstart,mid,index,addval);
    else
        updataone(root*2+1,mid+1,nend,index,addval);///在右子樹中更新

        ///根據左右子樹的值回溯更新當前節點的值
    segtree[root].val=segtree[root*2].val+segtree[root*2+1].val;

}
char str[10];
int main()
{

    int ncase,n,x,y;

    scanf("%d",&ncase);
    int T=0;

    while(ncase--)
    {
        scanf("%d",&n);

        for(int i=1;i<=n;i++)
            scanf("%d",&arr[i]);
        build(1,1,n);

        printf("Case %d:\n",++T);
        while(scanf("%s",str))
        {

            if(strcmp(str,"End")==0) break;
            else if(strcmp(str,"Query")==0)
            {
                scanf("%d%d",&x,&y);
                printf("%d\n",query(1,1,n,x,y));
            }
            else if(strcmp(str,"Add")==0)
            {
                scanf("%d%d",&x,&y);
                updataone(1,1,n,x,y);
            }
            else if(strcmp(str,"Sub")==0)
            {
                scanf("%d%d",&x,&y);
                updataone(1,1,n,x,-y);
            }
        }

    }
    return 0;
}

 

參考神犇kuangbin模板,

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn=50010;

struct node{
    int l,r;
    int val;
}segtree[maxn*4]; ///每個節點表示的範圍 值

int arr[maxn];

void build(int root,int istart,int iend) ///建樹
{

    segtree[root].l=istart;///儲存此節點的左右範圍
    segtree[root].r=iend;
    if(istart==iend){
        segtree[root].val=arr[istart];
    }
    else{

        int mid=(istart+iend)>>1;
        build(root<<1,istart,mid);
        build(root<<1|1,mid+1,iend);
        segtree[root].val=segtree[root<<1].val+segtree[root<<1|1].val;

    }
}

int query(int root,int qstart,int qend)
{

    if(qstart==segtree[root].l&&qend==segtree[root].r) ///此節點恰好滿足
        return segtree[root].val;

    int mid=(segtree[root].l+segtree[root].r)>>1;


    if(qend<=mid) return query(root<<1,qstart,qend); ///在左子樹
    else if(qstart>mid) return query(root<<1|1,qstart,qend); ///在右子樹


    return query(root<<1,qstart,mid)+query(root<<1|1,mid+1,qend);
}

void updataone(int root,int index,int addval) ///在位置index加上值addval
{
    ///在此節點加上
    segtree[root].val+=addval;
    if(segtree[root].l==index&&segtree[root].r==index) return;

    int mid=(segtree[root].l+segtree[root].r)>>1;

    if(index<=mid) ///在左子樹
        updataone(root<<1,index,addval);
    else
        updataone(root<<1|1,index,addval);


}
char str[10];
int main()
{

    int ncase,n,x,y;

    scanf("%d",&ncase);
    int T=0;

    while(ncase--)
    {
        scanf("%d",&n);

        for(int i=1;i<=n;i++)
            scanf("%d",&arr[i]);
        build(1,1,n);

        printf("Case %d:\n",++T);
        while(scanf("%s",str))
        {

            if(strcmp(str,"End")==0) break;
            else if(strcmp(str,"Query")==0)
            {
                scanf("%d%d",&x,&y);
                printf("%d\n",query(1,x,y));
            }
            else if(strcmp(str,"Add")==0)
            {
                scanf("%d%d",&x,&y);
                updataone(1,x,y);
            }
            else if(strcmp(str,"Sub")==0)
            {
                scanf("%d%d",&x,&y);
                updataone(1,x,-y);
            }
        }

    }
    return 0;
}