• 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,感激不尽。

  • 相关阅读:
    mysql复制那点事
    全排列问题
    56. Merge Interval
    2. Add Two Numbers
    20. Valid Parentheses
    121. Best Time to Buy and Sell Stock
    120. Triangle
    96. Unique Binary Search Trees
    91. Decode Ways
    72. Edit Distance
  • 原文地址:https://www.cnblogs.com/ankelen/p/5691187.html
Copyright © 2020-2023  润新知