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\n",Query(i,1));
127             }
128         }
129     }
130     return 0;
131 }
View Code

 

posted @ 2019-04-11 17:04  HHHyacinth  阅读(212)  评论(0编辑  收藏  举报