首页 > 代码库 > HDU 1166 敌兵布阵 (我的树状数组加线段树点修改模板)

HDU 1166 敌兵布阵 (我的树状数组加线段树点修改模板)

思路:本题因为是点修改,所以我们可以用线段树或者是树状数组了。线段树的基本操作我在我的代码中会具体体现,关键是要理解下面这幅图,具体的思想大家可以去看看其他的资料

线段树AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 50005


int num[N];
struct p
{
    int l,r,sum;
}tree[4*N];


void build(int root,int l,int r)    //root为当前所在节点的编号,l为它的左边界,r为它的右边界
{
    tree[root].l=l;
    tree[root].r=r;
    if(tree[root].l==tree[root].r)          //说明是叶子节点
    {
        tree[root].sum=num[l];
        return ;
    }
    int mid=(l+r)/2;        //区间划分
    build(root<<1,l,mid);   //左儿子
    build(root<<1|1,1+mid,r);   //右儿子
    tree[root].sum=tree[root<<1 ].sum+tree[root<<1|1].sum;  //当前节点值为两儿子之和
}


void update(int root,int pos,int val)   //因为要更新,所以我们要在根根节点root开始往下找
{//pos为当前位置,val为需要更新成的值
    if(tree[root].l==tree[root].r)
    {
        tree[root].sum=val;//找到了需要跟新的位置,更新它
        return ;
    }
    int mid=(tree[root].l+tree[root].r)/2;
    if(pos<=mid)    //左儿子
        update(root<<1,pos,val);
    else
        update(root<<1|1,pos,val);      //右儿子
    tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
}


int query(int root,int L,int R) //root 表示根节点,[L,R]表示要查询的区间
{
    if(L<=tree[root].l&&R>=tree[root].r)    
        return tree[root].sum;          // [L,R]要查询的区间包含root 节点表示的区间直接返回root 节点的sum 值
    int mid=(tree[root].l+tree[root].r)/2,ret=0;
    if(L<=mid)ret+=query(root<<1,L,R);
    if(R>mid)ret+=query(root<<1|1,L,R);
    return ret;
}
int main()
{
    int t,j,n,a,b,i;
    char str[10];
    scanf("%d",&t);
    for(j=1;j<=t;j++)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&num[i]);
        build(1,1,n);
        printf("Case %d:\n",j);
        while(1)
        {
            scanf("%s",str);
            if(strcmp(str,"End")==0)
                break;
            scanf("%d %d",&a,&b);


            if(str[0]=='Q')
            {
                if(a>b)swap(a,b);


                printf("%d\n",query(1,a,b));
            }
            else if(str[0]=='A')
            {
                num[a]=num[a]+b;
                update(1,a,num[a]);


            }
            else if(str[0]=='S')
            {
                num[a]=num[a]-b;
                update(1,a,num[a]);
            }
        }
    }
    return 0;
}


树状数组:

#include<string.h>
#include<stdio.h>
#include<math.h>
int a[50005];
int n;
typedef __int64 ll;
int lowbit(int t)
{
    return t&(-t);//如果某个结点是左子节点,那么它的父节点的编号为i+lowbit(i)
}                 //右子节点的父节点编号为i-lowbit(i)
void insert(int t,int d)
{
    while(t<=n)     //插入操作
    {
        a[t]+=d;
        t=t+lowbit(t);
    }
}
ll getsum(int t)
{
    ll sum=0;
    while(t>0)
    {
        sum+=a[t];
        t=t-lowbit(t);
    }
    return sum;
}

int main()
{
    int T,i,j,k,t;
    scanf("%d",&T);
    for(t=1;t<=T;t++)
    {
        memset(a,0,sizeof(a));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&k);
            insert(i,k);
        }
       // getchar();
        char str[10];
        scanf("%s",str);
        printf("Case %d:\n",t);
        while(strcmp(str,"End")!=0)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            if(strcmp(str,"Query")==0)
                printf("%I64d\n",getsum(y)-getsum(x-1));
            else if(strcmp(str,"Add")==0)
                insert(x,y);
            else if(strcmp(str,"Sub")==0)
                insert(x,(-1)*y);
            //getchar();
            scanf("%s",str);
        }
    }
    return 0;
}