zoukankan      html  css  js  c++  java
  • HDU 1166 敌兵布阵 线段树单点更新求和

    题目链接

    中文题,线段树入门题,单点更新求和,建一棵树就可以了。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #define N 50005
    using namespace std;
    int data[N];
    struct Tree
    {
        int l,r,sum;
    }tree[N*4];
    void build(int root,int l,int r)
    {
        tree[root].l=l;
        tree[root].r=r;
        if(l==r)
        {
            tree[root].sum=data[l];
            return;
        }
        int mid=(l+r)>>1;
        build(root<<1,l,mid);
        build(root<<1|1,mid+1,r);
        tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
    }
    void update(int root,int pos,int val)
    {
        if(tree[root].l==tree[root].r)
        {
            tree[root].sum=val;
            return;
        }
        int mid=(tree[root].l+tree[root].r)>>1;
        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)
    {
        if(l<=tree[root].l&&r>=tree[root].r) return tree[root].sum;
        int mid=(tree[root].l+tree[root].r)>>1,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 n,t,cas=1;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
            scanf("%d",&data[i]);
            build(1,1,N);
            int a,b;
            char c[105];
            printf("Case %d:
    ",cas++);
            while(scanf("%s",c)!=EOF)
            {
                if(strcmp(c,"End")==0) break;
                scanf("%d%d",&a,&b);
                if(strcmp(c,"Add")==0)
                {
                    data[a]+=b;
                    update(1,a,data[a]);
                }
                else if(strcmp(c,"Sub")==0)
                {
                    data[a]-=b;
                    update(1,a,data[a]);
                }
                else if(strcmp(c,"Query")==0)
                {
                    if(a>b) swap(a,b);
                    printf("%d
    ",query(1,a,b));
                }
            }
        }
        return 0;
    }

    带注释版:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #define N 50005
    using namespace std;
    int num[N];
    struct Tree
    {
        int l; //左端点
        int r; //右端点
        int sum; //总数
    } tree[N*4]; // 总线段的长度为 N,开数组的话一般开到 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); // k<<1 相等于 k*2 即是他的左孩子
        build(root<<1|1,mid+1,r); // k<<1|1 相当于 k*2+1 ,即是他的右孩子
        tree[root].sum = tree[root<<1].sum + tree[root<<1|1].sum; // 父亲的 sum = 左孩子的 sum+ 右孩子的 sum
    }
    void update(int root,int pos,int val) // root 是根节点,pos,val 表示:我们要跟新在 pos 点出的值更新为 val
    {
        if(tree[root].l==tree[root].r) // 如果是叶子节点,即是 pos 对应的位置
        {
            tree[root].sum=val; // 更新操作
            return; // 递归出口
        }
        int mid=(tree[root].l + tree[root].r)/2;
        if(pos<=mid) // 如果 pos 点是在 root 对应的左孩子的话,就调用 update(k<<1,pos,val);在左孩子里找
        update(root<<1,pos,val);
        else
            update(root<<1|1,pos,val);
        tree[root].sum = tree[root<<1].sum + tree[root<<1|1].sum; // 父亲的 sum = 左孩子的 sum+ 右孩子的 sum
    }
    int query(int root,int L,int R) // root 表示根节点,[L,R]表示要查询的区间
    {
        if(L<=tree[root].l&&R>=tree[root].r) // [L,R]要查询的区间 包含 root 节点表示的区间直接返回 root 节点的 sum 值
            return tree[root].sum;
        int mid=(tree[root].l + tree[root].r)/2,ret=0;
        if(L<=mid) ret+=query(root<<1,L,R); // 查询 root 节点的左孩子
        if(R>mid) ret+=query(root<<1|1,L,R); // 查询 root 节点的右孩子
        return ret; // 返回
    }
    int main()
    {
        int ca,cas=1,n,Q,a,b;
        char str[10];
        scanf("%d",&ca);
        while(ca--)
        {
            scanf("%d",&n);
            for(int i=1; i<=n; i++)
                scanf("%d",&num[i]); // 表示在 i 点的兵力数量
            build(1,1,N); // 构造线段树根节点 1,表示的区间范围【1 ,N】
            printf("Case %d:
    ",cas++);
            while(scanf("%s",str),strcmp(str,"End"))
            {
                scanf("%d%d",&a,&b);
                if(strcmp(str,"Query")==0)
                {
                    if(a>b) swap(a,b); // 查询的区间 【a,b】
                    printf("%d
    ",query(1,a,b)); //输出查询结果
                }
                else if(strcmp(str,"Add")==0)
                {
                    num[a]=num[a]+b;
                    update(1,a,num[a]); // 跟新 a 点值为 num[a]
                }
                else if(strcmp(str,"Sub")==0)
                {
                    num[a] = num[a]-b;
                    update(1,a,num[a]);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    微信授权,重定向两次
    Newtonsoft.Json 序列化 排除指定字段或只序列化指定字段
    各大快递公司面单号准确性验证的正则表达式,来自淘宝开放平台,时间是20181206,
    微信小程序web-view(webview) 嵌套H5页面 唤起微信支付的实现方案
    HTTP请求头及其作用 转
    sql server 只读帐号设置能读取存储过程,view等内容。
    PhantomJS命令行选项
    XML实体注入漏洞
    XmlDocument 避免XXE
    Centos7.6安装redis
  • 原文地址:https://www.cnblogs.com/Ritchie/p/6216867.html
Copyright © 2011-2022 走看看