zoukankan      html  css  js  c++  java
  • 敌兵布阵

    Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
     

    Description

    Lily 特别喜欢养花,但是由于她的花特别多,所以照料这些花就变得不太容易。她把她的花依次排成一行,每盆花都有一个美观值。如果Lily把某盆花照料的好的话,这盆花的美观值就会上升,如果照料的不好的话,这盆花的美观值就会下降。有时,Lily想知道某段连续的花的美观值之和是多少,但是,Lily的算术不是很好,你能快速地告诉她结果吗?

    Input

    	第一行一个整数T,表示有T组测试数据。
    每组测试数据的第一行为一个正整数N(N<=50000),表示Lily有N盆花。接下来有N个正整数,第i个正整数ai表示第i盆花的初始美观值(1<=ai<=50)。
    接下来每行有一条命令,命令有4种形式:
    (1)Add i j, i和j为正整数,表示第i盆花被照料的好,美观值增加j(j<=30)
    (2)Sub i j, i和j为正整数,表示第i盆花被照料的不好,美观值减少j(j<=30)
    (3)Query i j, i和j为正整数,i<=j,表示询问第i盆花到第j盆花的美观值之和
    (4)End,表示结束,这条命令在每组数据最后出现
    每组数据的命令不超过40000条
    
    

    Output

    	对于第i组数据,首先输出"Case i:"和回车。
    对于每个"Query i j"命令,输出第i盆花到第j盆花的美观值之和。

    Sample Input

    1
    9
    7 9 8 4 4 5 4 2 7
    Query 7 9
    Add 4 9
    Query 3 6
    Sub 9 6
    Sub 3 3
    Query 1 9
    End
    
    

    Sample Output

    Case 1:
    13
    30
    50
     

    //运用线段树知识:对于查找线段树,有如下知识:

    对于每一条线段A,从根节点开始遍历这棵线段树,对于每一个当前遍历的结点NODE(其实线段树中每一个结点就是一条线段),考虑四种情况:
    a)如果线段A包含在线段NODE的左半区间,那么从NODE的左儿子(其实就是NODE的左半区间)开始遍历这棵树
    b)如果线段A包含在线段NODE的右半区间,那么从NODE的右儿子(其实就是NODE的右半区间)开始遍历这棵树
    c)如果线段A刚好和线段NODE重合,停止遍历,并将NODE中的count字段加1
    d)除了以上的情况,就将线段A的左半部分在NODE的左儿子处遍历,将A的右半部分在NODE的右儿子处遍历

    源代码如下:

    #include <iostream>
    #include <stdio.h>
    #include <cstring>
    using namespace std;
    struct node
    {
        int left,right;
        int value;
    
    }tree[140000];
    
    int r[50010],sum;//r[50010]是存放每个点上的人数,sum是用来存放查询的结果。
    
    void make (int x,int y,int num)
    {
        tree[num].left=x;
        tree[num].right=y;
        if(tree[num].left==tree[num].right)
            tree[num].value=r[y];//如果x==y,说明已经是叶子节点了,没有儿子节点了,就显现成熟单个营地,人数就是r[y]
        else
            {
                make(x,(x+y)/2,num+num);//构造左儿子树
                make((x+y)/2+1,y,num+num+1);//构造右儿子树
                tree[num].value=tree[num+num+1].value+tree[num+num].value;//父节点的人数等于子结点人数之和,线段被分成两段。
            }
    }
    
    void add (int x,int y,int num)//从根节点不断往下更改,只要包含该点x的线段子都增加相应的数量y
    {
        tree[num].value+=y;
        if(tree[num].left==x&&tree[num].right==x)  return;//找到x的叶子节点。停止。
        else if(x>(tree[num].left+tree[num].right)/2) add(x,y,num+num+1);//点x在该线段的右边,查询右子节点。
        else add(x,y,num+num);//否则查询左子节点
    }
    
    void sub(int x,int y,int num)
    {
        tree[num].value-=y;
        if(tree[num].left==x&&tree[num].right==x)  return;
        else if(x>(tree[num].left+tree[num].right)/2) sub(x,y,num+num+1);
        else sub(x,y,num+num);
    }
    
    void query(int x,int y,int num)
    {
        if(x<=tree[num].left&&y>=tree[num].right)//找到要求的线段区间,返回其值
            sum+=tree[num].value;
        else
        {
            int mid =(tree[num].left+tree[num].right)/2;
            if(x>mid) query(x,y,num+num+1);//要查询的线段在该线段右边,查询该线段的右子节点
            else if(y<=mid) query(x,y,num+num);//要查询的线段在该线段左边,查询该线段的左子节点
            else
                {
                    query(x,y,num+num);//要查询的线段在该线段中间,分段查询,左右节点都查。
                    query(x,y,num+num+1);
                }
        }
    }
    
    int main()
    {
        int a,b,t,n;
        char command[6];
        scanf("%d",&t);
        int j=0;
        while(t--)
        {   memset(r,0,sizeof(r));
            scanf("%d",&n);
            for (int i=1;i<=n;i++)
                scanf("%d",&r[i]);
            make(1,n,1);
            printf("Case %d:
    ",++j);
            while (cin>>command)
            {
                if(strcmp(command,"End")==0)
                    break;
                if(strcmp(command,"Query")==0)
                {
                    scanf("%d %d",&a,&b);
                    sum=0;
                    query(a,b,1);
                    printf("%d
    ",sum);
                }
                if(strcmp(command,"Add")==0)
                {
                    scanf("%d %d",&a,&b);
                    add(a,b,1);
                }
                if(strcmp(command,"Sub")==0)
                {
                    scanf("%d %d",&a,&b);
                    sub(a,b,1);
                }
            }
    
        }
        return 0;
    }
    View Code
  • 相关阅读:
    正则表达式基础知识
    成功的基本法则
    Java实现简单的格式化信函生成器
    C实现哈希表
    C实现求解给定文本中以指定字符开头和结尾的子串数量的三种算法
    Java实现求解二项式系数及代码重构
    Java 异常处理学习总结
    C实现大整数幂求模问题的两种算法
    linux 学习前言
    提高编程能力的10种方法
  • 原文地址:https://www.cnblogs.com/gdvxfgv/p/5693252.html
Copyright © 2011-2022 走看看