zoukankan      html  css  js  c++  java
  • 2016HUAS_ACM暑假集训2D

          刚开始接触线段树,不得不说,每次接触到一个新的数据结构,都会是一场头脑风暴的“盛宴”。希望我能继续痛苦并快乐着学下去。我相信,有各路大神的博客相助,我还是能坚持下去的。

          这个题目是HDU的1166,只是题意改了一下(把士兵改为花的美观值了),实际上是一模一样的。用模拟的话妥妥的超时,别问我怎么知道的,哎,心累。线段树,我觉得最经典的也是最难的地方就是数据的更新,当你每次进行修改操作时,你要改动那个节点的所有父节点上的值,这点尤其重要!

          关于线段树的一个重要的关系:如果上个节点是[a,b],则它的左子树为[a,(a+b)/2],右子树为[(a+b)/2+1,b]。顺便一提的就是线段树上的每个节点都是线段。听起来挺有趣的哈......

    大致题意是这样的:有四种操作,它们的形式是这样的:(i和j为正整数)

    1.Add i j,        表示第i个数增加j(j<=30)

    2.Sub i j,        表示第i个数减少j(j<=30)

    3.Query i j,      i<=j,表示询问第i个数到第j的数的和

    4.End,  表示结束,这条命令在每组数据最后出现

    下面给出样例输入输出:(第一个数T表示有T数,第二个数N表示有个数,每次遇到询问Query时输出一下结果)

    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(对于每i组,首先输出一个Case i:)
    Case 1:
    13
    30
    50

    下面就贴代码吧,老规矩,思路在注释里。

      1 #include<stdio.h>
      2 #include<string.h>
      3 
      4 #define SIZE 50010//存储N个花盆的美观值
      5 #define MAXN 150000//存储树节点
      6 
      7 int T,N,ans,x,y,n[SIZE];
      8 char p[10];
      9 tree t[MAXN];
     10 
     11 struct tree
     12 {
     13     int a,b,s;//线段树每个节点的左端点a,右端点b,以及[a,b]的总美观值
     14 };
     15 
     16 void Init(int x,int y,int z)//构造线段树
     17 {
     18     if(t[z].a==t[z].b)//叶子节点([1,1],[2,2]...)的形式
     19         t[z].s=n[y];
     20     else
     21     {
     22         Init(x,(x+y)/2,2*z);//构造左子树
     23         Init((x+y)/2+1,y,2*z+1);//构造右子树
     24         t[z].s=t[2*z].s+t[2*z+1].s;//父节点上的总美观值=两子树美观值的和
     25     }
     26 }
     27 //变为2*z的原因是:一个二叉树第n层的第一个节点的编号是第(n-1)层的第一个节点的两倍(1,2,4,8....)
     28 
     29 void Add(int x,int y,int z)//区间修改Add
     30 {
     31     t[z].s+=y;//数据更新的关键所在:从根节点往下更新,更新的原则是线段只要包含了点x,则要加上更新量y
     32     if(t[z].a==x && t[z].b==x)//更新到子节点了([x,x]那片叶子),停止
     33         return ;
     34     if(x>(t[z].a+t[z].b)/2)//如果该端点x在线段的右边,更新右子树
     35 //如果上个节点是[a,b],则它的左子树为[a,(a+b)/2],右子树为[(a+b)/2+1,b]  这里非常重要(=+-__+=)!!!
     36         Add(x,y,2*z+1);
     37     else
     38         Add(x,y,2*z);//否则更新左子树
     39 }
     40 void Sub(int x,int y,int z)//区间修改Sub 跟Add差不多的思路
     41 {
     42     t[z].s-=y;
     43     if(t[z].a==x&&t[z].b==x)
     44         return ;
     45     if(x>(t[z].a+t[z].b)/2)
     46         Sub(x,y,2*z+1);
     47     else
     48         Sub(x,y,2*z);
     49 }
     50 
     51 void Query(int x,int y,int z)//区间查询Qyery
     52 {
     53     if(t[z].a>=x&&t[z].b<=y)//[x,y]刚好在[a,b]内
     54         ans+=t[z].s;//记录答案
     55     else
     56     {
     57         if(x>(t[z].a+t[z].b)/2)//[x,y]在右子树上
     58             Query(x,y,2*z+1);
     59         else if(y<=(t[z].a+t[z].b)/2)//在左子树上
     60             Query(x,y,2*z);
     61         else//如果[x,y]在两个子树上都有,都查就行了
     62         {
     63             Query(x,y,2*z);
     64             Query(x,y,2*z+1);
     65         }
     66     }
     67 }
     68 //这里体现的线段树的优越性,在查询的时候不需要全部遍历
     69 int main()
     70 {
     71     int i,j;
     72     scanf("%d",&T);
     73     for(i=1;i<=T;i++)
     74     {
     75         scanf("%d",&N);
     76         for(j=1;j<=N;j++)
     77             scanf("%d",&n[j]);
     78         Init(1,N,1); 
     79         printf("Case %d:
    ",i);
     80         while(scanf("%s",&p),strcmp(p,"End"))
     81         {
     82             if(strcmp(p,"Add")==0)//Add  第x个数加y
     83             {
     84                 scanf("%d %d",&x,&y);
     85                 Add(x,y,1);
     86             }
     87             else if((strcmp(p,"Sub")==0))//Sub  第x个数减y
     88             {
     89                 scanf("%d %d",&x,&y);
     90                 Sub(x,y,1);
     91             }
     92             else if((strcmp(p,"Query")==0))//Query 输出x->y的美观值
     93             {
     94                 ans=0;
     95                 scanf("%d %d",&x,&y);
     96                 Query(x,y,1);
     97                 printf("%d
    ",ans);
     98             }    
     99         }
    100     }
    101     return 0;
    102 }
    View Code

    哦,这里还有一个坑,如果用C++的cin和cout的话,光荣的TLE......小伙伴们不信可以去试试。如果不TLE,希望大神能给我分享一下你的code,感激不尽。

  • 相关阅读:
    CF1270H. Number of Components
    NOI Online Round2划水记
    uoj#247. 【Rujia Liu's Present 7】Mysterious Space Station口胡
    mysql习题
    MySQL基础
    python网络编程(进程与多线程)
    xshell连接虚拟机Ubuntu问题
    python来写打飞机
    timeit模块
    python常用模块
  • 原文地址:https://www.cnblogs.com/ankelen/p/5691187.html
Copyright © 2011-2022 走看看