5291 Ground Defense

公开20190410远古博客,汗

问题 G: Ground Defense

时间限制: 1 Sec  内存限制: 128 MB
提交: 128  解决: 25
[提交] [状态] [命题人: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.

思路历程

最初想的是树状数组和线段树打配合,但是线段树没有对r+1点进行操作,所以导致在区间外侧应该没有影响,此时区间左侧没有影响,但是对区间右侧每个多加了一个所谓的公差*区间长度,然后想着换方法使区间不能对区间右侧元素有影响,所以想到了主席数,这样就避免了前面区间对本次查询的影响,但是只包含一次的查询影响了,找出每个所在区间然后对对应的每次查询都加和吗,怕是T了。所以想怎么在之前确定好的线段树基础上加以改进,避免对后面不在区间离得元素有影响,减掉就好了呀,怎么减?对后面每个多加的点都减一次,显然不对,因为要求前缀和,所以只对他们必经的一个点减就好了,这样求前缀和使自然就减掉了呀,所以选择了r+1点。然后建两颗线段树吗?一个存E方向的更新,一个存W方向的更新,太麻烦了,能不能把两个方向归为一类操作(线段树多防止更新题常见套路!!!),可以公差取相反数末项作为首项不就完了,因为等差数列顺序整体颠倒不影响他是等差数列的本质。

解法

首先很容易想到,对于等差数列将其分为两部分,首项+(公差*(id-1)),分别由一个树状数组和一个线段树来维护,树状数组区间赋值每次对一个【l,r】赋值,具体:

1.对E方向的,直接赋值为首项

2.对W方向的,赋值为“末项”,即为给定首项+公差*区间两端点距离(r-l)

线段树每次对一个【l,r】更新区间l++,具体:

1.对E方向的,直接公差区间赋值,然后第r+1个点赋值为-1*公差*区间长度(r-l+1)。

2.对W方向的,公差*=-1,然后同上:公差区间赋值,然后第r+1个点赋值为-1*公差*区间长度(r-l+1)。

最后Q x的话,查询树状数组的前x项前缀共和+查询线段树【1,x】区间和(即x前缀和)就是答案了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define self tree[rt]
#define lson tree[rt<<1]
#define rson tree[rt<<1|1]
const int maxn = 5e5 + 5;
ll c[maxn];
struct Tree
{
    int l,r;
    ll lazy,sum;
}tree[maxn<<2];
 
void build(int rt,int l,int r)
{
    self.l = l;
    self.r = r;
    self.lazy = self.sum = 0;
    if(l == r)
        return ;
    int mid = (l + r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
}
 
void push_down(int rt)
{
    if(!self.lazy)
        return ;
    lson.lazy += self.lazy;
    rson.lazy += self.lazy;
    lson.sum += self.lazy * (lson.r - lson.l + 1);
    rson.sum += self.lazy * (rson.r - rson.l + 1);
    self.lazy = 0;
}
 
void update(int rt,int l,int r,ll val)
{
    if(l <= self.l && self.r <= r)
    {
        self.sum += val * (self.r - self.l + 1);
        self.lazy += val;
        return ;
    }
    push_down(rt);
    int mid = (self.l + self.r)>>1;
    if(l <= mid)
        update(rt<<1,l,r,val);
    if(r > mid)
        update(rt<<1|1,l,r,val);
    self.sum = lson.sum + rson.sum;
}
 
ll query(int rt,int l,int r)
{
    if(l <= self.l && self.r <= r)
        return self.sum;
    push_down(rt);
    int mid = (self.l + self.r)>>1;
    ll ans = 0;
    if(l <= mid)
        ans += query(rt<<1,l,r);
    if(r > mid)
        ans += query(rt<<1|1,l,r);
//    self.sum = lson.sum + rson.sum;
    return ans;
}
 
void add(int x,ll val)
{
    while(x < maxn)
    {
        c[x]+=val;
        x+=x&-x;
    }
}
 
ll query(int x)
{
    ll ans = 0;
    while(x)
    {
        ans += c[x];
        x-=x&-x;
    }
    return ans;
}
 
int main()
{
    int t;
    scanf("%d",&t);
    while(t --)
    {
        memset(c,0,sizeof(c));
        int m,n;
        scanf("%d%d",&m,&n);
        build(1,1,n);
        while(m --)
        {
            char op[3];
            scanf("%s",op);
            if(op[0] == 'U')
            {
                char dire[3];
                int i,d,l,r;
                ll s,a;
                scanf("%s%d%lld%lld%d",dire,&i,&s,&a,&d);
                if(dire[0] == 'E')
                    l = i,r = l + d - 1;
                else
                {
                    r = i,l = r - d + 1;
                    s = s + (d - 1)*a;
                    a = -a;
                }
                add(l,s);
                if(r+1 <= n)add(r+1,-s);
 
                l++;
                if(l > r)
                    continue;
                update(1,l,r,a);
                if(r+1 <= n)update(1,r+1,r+1,-a*(r-l+1));
            }
            else
            {
                int x;
                scanf("%d",&x);
                printf("%lld\n",query(x) + query(1,1,x));
            }
        }
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值