Ground Defense 线段树维护差分数组,求前缀和(线段树维护区间和)

这个大佬的简单很多。

https://blog.csdn.net/Prince_NYing/article/details/89194576

我的做法太麻烦,就是自己吐槽一下

问题 G: Ground Defense

时间限制: 1 Sec  内存限制: 128 MB
提交: 300  解决: 54
[提交] [状态] [命题人:admin]

题目描述

You are a denizen of Linetopia, whose n major cities happen to be equally spaced along an east-west line. In fact, they are often numbered in order from 1 to n, where 1 is the westmost city and n is the eastmost city. 
Linetopia was a lovely place to live until forces from neighboring Trapez invaded. As part of Linetopia’s Shielding Lives and Protecting Citizens initiative, you have been called upon to process information about Trapezoid troop movements so we can determine which cities have been hardest hit and know where to send reinforcements.
Linetopia intelligence has discovered that the Trapezoid forces are attacking in the following pattern. They are sending massive aircraft to drop troops on Linetopia cities. Each aircraft starts at some city i, dropping s soldiers. The aircraft then proceeds to fly either east or west. Each time it flies over another city, it drops a more soldiers than it dropped on the previous city it passed. After performing d drops, the aircraft returns to Trapez to resupply.
You will be receiving intel updates that inform you of the specs of each Trapezoid aircraft passing over Linetopia. You want to answer queries that ask how many Trapezoid troops have been dropped on a particular city. Are you up to the task?

 

输入

The first line of input contains a single integer T (1 ≤ T ≤ 10), the number of test cases. The first line of each test case contains two integers: m (1 ≤ m ≤ 10,000), the number of updates and queries and n (1 ≤ n ≤ 500,000), the number of cities in Linetopia.
The next m lines of input are either updates or queries. Update lines begin with a capital U, then contain either a capital E (east) or W (west) to indicate direction, and then contain four integers i (1 ≤ i ≤ n), s (1 ≤ s ≤ 10,000), a (0 ≤ a ≤ 10,000), and d (1 ≤ d ≤ n). These integers signify the starting city, the starting number of soldiers, the increase in soldiers per city, and the number of drops, respectively. You can assume d never results in an aircraft flying to the west of city 1 or to the east of city n.
Query lines begin with a capital Q, and then contain a single integer i (1 ≤ i ≤ n) indicating the city being queried.

 

输出

For each query in the input, output a single line containing the number of Trapezoid troops dropped in that city.

 

样例输入

复制样例数据

1
8 3
U E 1 5 2 3
Q 1
Q 2
Q 3
U W 3 10 10 2
Q 1
Q 2
Q 3

样例输出

5
7
9
5
27
19

提示

Two aircrafts fly over Linetopia. The first starts at city 1 and heads east. It drops 5 soldiers on city 1, 7
soldiers on city 2, and 9 soldiers on city 3. The second starts at city 3 and flies west. It drops 10 soldiers on
city 3 and 20 soldiers on city 2.

 

思路:读懂题意后 发现对区间操作  立即推  可能是线段树 ,从起点向后是 递增的等差数列 每个城市人数不一样,立即推,不能区间操作,,突然发现, 差分数组可以存储公差,在这个区间内 都是 加 d ,立即推 线段树维护差分数组。(我想到这里就停下了。)(剩下的超哥和 xyx 他们队伍的想法)

但是查询怎么办?   题意是单点查询,突然想到   差分数组的前缀和就是该点的 实际人数,

那么,线段树维护区间和,再求一个  1 到 q 的区间和 就是 q点的实际人数了。  

#include<bits/stdc++.h>
using namespace std;
const int C= 500001;
long long ad[4*C+10];
long long sum[4*C+10];
long long  sum_q;

void maintain(int o,int l,int r){

    sum[o]=0;
    if(l<r)
        sum[o]=sum[o*2]+sum[o*2+1];

    sum[o]+=ad[o]*(r-l+1);

    return ;
}

void updateE(int o,int l,int r,int L,int R,long long  a){
    if(L>R) return ;
    if(L<=l && r<=R)
    {
        ad[o]+=a;
        maintain(o,l,r);
        return ;
    }
    int m=(l+r)/2;
    if(L<=m)
    updateE(o*2,l,m,L,R,a);
    if(m<R)
    updateE(o*2+1,m+1,r,L,R,a);
    maintain(o,l,r);
}


void quiry(int o,int l,int r,int L,int q,long long  ada){

    if(L<=l && r<=q){

        sum_q+=(sum[o]+ada*(r-l+1) );
        return ;
    }
    int m=(l+r)/2;
    if(L<=m)
        quiry(o*2,l,m,L,q,ada+ad[o]);
    if(m<q)
        quiry(o*2+1,m+1,r,L,q,ada+ad[o]);
}

int main()
{

//    freopen("in.txt","r",stdin);

    int t;
    scanf("%d",&t);

    while(t--){
        memset(ad,0,sizeof ad);
        memset(sum,0,sizeof sum);

        int n,city; scanf("%d%d",&n,&city);

        getchar();
        while(n--){
            char c;
           char cc = getchar();
           if (!(cc=='U' || cc=='Q'))
           {
               scanf("%c",&c);
           }
            else
                c=cc;

            getchar();
            if(c=='U'){
                char we;   scanf("%c",&we);
                int ii; long long s ;
                long long a;int d;
                scanf("%d %lld %lld %d",&ii,&s,&a,&d);

                if(we=='E'){
                    updateE(1,1,city,ii,ii,s);       // 起点
                    updateE(1,1,city,ii+1,ii+d-1,a); // 区间       
                    updateE(1,1,city,ii+d,ii+d, (-1*s-(d-1)*a) ); // 终点
                }
                else{
                    updateE(1,1,city,ii-d+1,ii-d+1,a*(d-1)+s); // 起点
                    updateE(1,1,city,ii-d+2,ii,-1*a);   // 区间  
                    updateE(1,1,city,ii+1,ii+1,-1*s);    // 终点
                }

            }
            if( c == 'Q' ){
                sum_q=(long long )0;
                int q;
                scanf("%d",&q);
                quiry(1,1,city,1,q,0);
                cout<<sum_q<<endl;
            }

        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值