hdu 1166 敌兵布阵(线段树,单点更新)

难得的一道汉语题。

题意就不说。好多人看完题后肯定想的使用一个足够大的数组来模拟,但是这样模拟的话肯定会超时。

二重循环的时间复杂度为O(n^2)。

这个题属于线段树中的对单一结点操作的简单线段树,就是每次update只是对一个点操作。

要注意的是由于线段树的题目一般数据量都比较大,在输入的时候用cin不合适,时间卡的紧的话会超时,所以这块用scanf

还有一点要注意的是乘法除法运算在计算机中的操作也是比较复杂,这里用位运算来实现,防超时。

/*用静态数组来模拟满二叉树*/
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

typedef struct/*树的节点信息*/
{
    int l,r,value,add;
} node;

const int Maxsize = 50050;

node tree[Maxsize*4];/*结点一般开这么大,保证空间足够*/

int ans,data[Maxsize];

int main()
{
    void build(int v,int l,int r);
    void update(int v,int k,int m);
    void query(int v,int l,int r);
    int ncase,m,n,k;
    int kkk = 0;
    char str[50];
    scanf("%d",&ncase);
    while(ncase--)
    {
        bool flag = false;
        scanf("%d",&k);
        memset(data,0,sizeof(data));
        for(int i = 1 ; i <= k ; i++)
        {
            scanf("%d",&data[i]);
        }
        build(1,1,k);
        while(scanf("%s",str) && strcmp(str,"End") != 0)
        {
            scanf("%d %d",&n,&m);
            if(str[0] == 'Q')
            {
                ans = 0;
                query(1,n,m);
                if(!flag)
                {
                    flag = true;
                    printf("Case %d:\n",++kkk);
                }
                printf("%d\n",ans);
            }
            else if(str[0] == 'A')
            {
                update(1,n,m);
            }
            else if(str[0] == 'S')
            {
                update(1,n,-m);
            }
        }
    }
    return 0;
}

void build(int v,int l,int r)/*建立线段树*/
{
    tree[v].l = l;
    tree[v].r = r;
    if(l == r)
    {
        tree[v].value = data[r];
        return;
    }
    int mid = (l+r)/2;
    build(v<<1,l,mid);
    build(v<<1|1,mid+1,r);
    tree[v].value = tree[v<<1].value + tree[v<<1|1].value;
}

void update(int v,int k,int m)/*更新操作*/
{
    if(tree[v].r == tree[v].l && tree[v].l == k)
    {
        tree[v].value+= m;
        return;
    }
    int mid = (tree[v].l + tree[v].r)>>1;
    if(k <= mid)
    {
        update(v<<1,k,m);
    }
    else
    {
        update(v<<1|1,k,m);
    }
    tree[v].value = tree[v<<1].value + tree[v<<1|1].value;
}

void query(int v,int l,int r)/*查询*/
{
    if(tree[v].l == l && tree[v].r == r)
    {
        ans+=tree[v].value;
        return;
    }
    int mid = (tree[v].r+tree[v].l)>>1;
    if(r<=mid)
    {
        query(v<<1,l,r);
    }
    else
    {
        if(l>mid)
        {
            query(v<<1|1,l,r);
        }
        else /*要查找的区间横跨*/
        {
            query(v<<1,l,mid);
            query(v<<1|1,mid+1,r);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值