zoukankan      html  css  js  c++  java
  • Stanford Local 2016 G "Ground Defense"(线段树)

    传送门

    题意:

      有 n 个城市,编号 1~n;

      有两种操作:Update,Query

      Update:

        E i s a d

        更新区间[ i,i+d-1 ], i 节点降落 s 人, i+1 节点降落 s+a 人, i+2 节点降落 s+2*a 人,......, i+d-1 节点降落 s+(d-1)*a 人;

        W i s a d

        更新区间[ i-d+1,i ],  i 节点降落 s 人, i-1 节点降落 s+a 人, i-2 节点降落 s+2*a 人,......, i-d+1 节点降落 s+(d-1)*a 人;

      简言之,从 i 节点下降 s 人开始,向东(右),西(左)下降的人数依次 +a;

      Query: i

        查询在节点 i 降落的总人数。

    题解:

      看到这道题,第一反应是线段树区间更新,那具体怎么个更新法呢?

      首先看线段树中定义的元素:

    struct SegmentTree
    {
        int l,r;
        ll s;//l处增加s人
        ll a;//从l到r依次变化a人
        int mid()
        {
            return l+((r-l)>>1);
        }
    }segTree[4*maxn];

      定义Update()函数,具体如下:

    void Update(int l,int r,int pos,ll s,ll a)
    {
        if(segTree[pos].l == l && segTree[pos].r == r)
        {
            segTree[pos].s += s;//pos节点中的s增加s
            segTree[pos].a += a;//pos节点中的a增加a
            return ;
        }
        pushDown(pos);//向下更新
     
        int mid=segTree[pos].mid();
        if(r <= mid)
            Update(l,r,ls(pos),s,a);
        else if(l > mid)
            Update(l,r,rs(pos),s,a);
        else
        {
            ll d=mid+1-l;
            Update(l,mid,ls(pos),s,a);
            Update(mid+1,r,rs(pos),s+d*a,a);//注意右儿子更新的s值
        }
    }

      如果更新操作为 E i s a d :

        调用函数 Update( i , i+d-1 , 1 , s , a );

      反之,如果更新操作为 W i s a d ⇔ E (i-d+1) ( s+(d-1)*a ) (-a) d

        调用函数 Update( (i-d+1) , i , 1 , s+(d-1)*a , -a );

      更新函数中的pushDown()函数是非常重要的,其决定了此算法的正确与否:

    //将pos节点更新的状态传给儿子节点
    void pushDown(int pos)
    {
        ll &s=segTree[pos].s;
        ll &a=segTree[pos].a;
        if(s)//如果s不为0,说明在这之前曾更新过pos节点
        {
            //左儿子的更新
            segTree[ls(pos)].s += s;
            segTree[ls(pos)].a += a;
     
            /**
                右儿子的更新操作
                注意 segTree[rs(pos)].s 增加的值
                具体原因留给读者自己思索
            */
            segTree[rs(pos)].s += s+a*(segTree[rs(pos)].l-segTree[ls(pos)].l);
            segTree[rs(pos)].a += a;
        }
        s=0;
        a=0;
    }

    AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<vector>
      5 using namespace std;
      6 #define ls(x) (x<<1)
      7 #define rs(x) (x<<1|1)
      8 #define ll long long
      9 #define mem(a,b) memset(a,b,sizeof(a))
     10 const int maxn=5e5+50;
     11  
     12 int n,m;
     13 struct SegmentTree
     14 {
     15     int l,r;
     16     ll s;//l处增加s人
     17     ll a;//从l到r依次增加a
     18     int mid()
     19     {
     20         return l+((r-l)>>1);
     21     }
     22 }segTree[4*maxn];
     23  
     24 void pushDown(int pos)
     25 {
     26     ll &s=segTree[pos].s;
     27     ll &a=segTree[pos].a;
     28     if(s)
     29     {
     30         segTree[ls(pos)].s += s;
     31         segTree[ls(pos)].a += a;
     32  
     33         /**
     34             右儿子的更新操作
     35             注意 segTree[rs(pos)].s 增加的值
     36             具体原因留给读者自己思索
     37         */
     38         segTree[rs(pos)].s += s+a*(segTree[rs(pos)].l-segTree[ls(pos)].l);
     39         segTree[rs(pos)].a += a;
     40     }
     41     s=0;
     42     a=0;
     43 }
     44 void buildSegTree(int l,int r,int pos)
     45 {
     46     segTree[pos].l=l;
     47     segTree[pos].r=r;
     48     segTree[pos].s=0;
     49     segTree[pos].a=0;
     50     if(l == r)
     51         return ;
     52  
     53     int mid=l+((r-l)>>1);
     54     buildSegTree(l,mid,ls(pos));
     55     buildSegTree(mid+1,r,rs(pos));
     56 }
     57 void Update(int l,int r,int pos,ll s,ll a)
     58 {
     59     if(segTree[pos].l == l && segTree[pos].r == r)
     60     {
     61         segTree[pos].s += s;
     62         segTree[pos].a += a;
     63         return ;
     64     }
     65     pushDown(pos);//向下更新
     66  
     67     int mid=segTree[pos].mid();
     68     if(r <= mid)
     69         Update(l,r,ls(pos),s,a);
     70     else if(l > mid)
     71         Update(l,r,rs(pos),s,a);
     72     else
     73     {
     74         ll d=mid+1-l;
     75         Update(l,mid,ls(pos),s,a);
     76         Update(mid+1,r,rs(pos),s+d*a,a);//注意右儿子更新的s值
     77     }
     78 }
     79 ll Query(int x,int pos)
     80 {
     81     if(segTree[pos].l == segTree[pos].r)
     82         return segTree[pos].s;
     83     pushDown(pos);
     84  
     85     int mid=segTree[pos].mid();
     86     if(x <= mid)
     87         return Query(x,ls(pos));
     88     else
     89         return Query(x,rs(pos));
     90 }
     91 int main()
     92 {
     93 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
     94     int test;
     95     scanf("%d",&test);
     96     while(test--)
     97     {
     98         scanf("%d%d",&m,&n);
     99         buildSegTree(1,n,1);
    100         while(m--)
    101         {
    102             char order[2];
    103             scanf("%s",order);
    104             if(order[0] == 'U')
    105             {
    106                 char x[2];
    107                 int i,s,a,d;
    108                 scanf("%s%d%d%d%d",x,&i,&s,&a,&d);
    109                 if(x[0] == 'E')
    110                 {
    111                     //r=min()是为了防止数据出错使得 i+d-1 > n
    112                     int r=min(n,i+d-1);
    113                     Update(i,r,1,s,a);
    114                 }
    115                 else
    116                 {
    117                     //l=max()是为了防止数据出错使得 i-d+1 < 1
    118                     int l=max(1,i-d+1);
    119                     Update(l,i,1,1ll*s+1ll*a*(d-1),-a);
    120                 }
    121             }
    122             else
    123             {
    124                 int i;
    125                 scanf("%d",&i);
    126                 printf("%lld
    ",Query(i,1));
    127             }
    128         }
    129     }
    130     return 0;
    131 }
    View Code
  • 相关阅读:
    信息学奥赛一本通(c++版) 1003:对齐输出
    读书笔记(华科曹计昌 《c语言与程序设计》)
    使用request对象实现注册示例,get/post的编码问题
    Eclipse中开发第一个web(jsp)项目
    Eclipse恢复默认布局
    手工在tomcat目录中建立个人项目
    通过ServletContext获得工程根目录路径、读取文件以及获得classpath目录下的文件
    ServletContext设置全局变量实现统计站点访问次数
    servlet全局参数的设置
    Eclipse关联Servlet源码详细步骤
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10690889.html
Copyright © 2011-2022 走看看