「IOI2001」Mobile Phones

「IOI2001」Mobile Phones

IOI史诗级大水题!!!

题目大意:

对于每次查询,q==1时在[X,Y]插入A,q==2时查询区间{[L,B],[R,T]}的数值和。

所以什么题目背景啊,标志03的意义啊、还有 L ≤ X ≤ R L\le X\le R LXR B ≤ Y ≤ T B\le Y\le T BYT之类都是用来迷惑人的。

题目思路

对于q==1,就是一个二维树状数组基本的插入操作,重点在q==2时区间的数值和怎么求。

先想一想一维的树状数组:对于一个区间[L,R],要求它的数值和,我们可以用区间[1,R]的数值和去减区间[l,L-1]的数值和。

int query(int x)//求出1~i的数值和
{
    int ans = 0;
    for(int i = x; i; i -= lowbit(i))
    {
        ans += c[i];
    }
    return ans;
}
int main(){
    /*......*/
    int l, r, ans;
    cin >> l >> r;
    ans = query(r) - query(l-1);//用[1,r](前r个数的和)减去[1,l-1](前l-1个数的和)
}

类似地,二维的区间数值和也可以用相同的通过加减运算来得到吗?答案是肯定的,我们可以求出{[1,1],[x,y]}的值,再通过矩形的加减运算求出所需区域。如下图:

运算图

矩形{[L,B],[R,T]}(粉色)为题目所求的的区域,不难看出,粉色矩形 = 整个彩色矩形 - 蓝色区域(蓝线框起来的地方) - 黄色区域(黄线框起来的地方 + 绿色矩形。即:{[L,B],[R,T]} = {[1,1],[R,T]} - {[1,1],[L - 1,T]} - {[1,1],[R,B - 1]} + {[1,1],[L - 1,B - 1]}。可以发现,等号后的矩形的值都是[1,1],[x,y]的格式。因为题目给的描述是从[0,0]开始的矩形,所以我们只需要对于每个L,B,R,T加1,再把L,B减一。至于为什么要减一呢?我们不妨把矩形压到一维数组试试:

int a[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, b[11];
int r = 9, l = 5;//求5~9=35
for(int i = 1; i <= 10; i++)
{
    b[i] = b[i-1] + a[i];
}
/*b[r] - b[l] = b[9] - b[5] = 45 - 15 = 30;错误*/
b[r] - b[l-1] = b[9] - b[4] = 45 - 10 = 35;//因为[L,R]是闭区间,所以L要减一

同理,二维的数组也一样如此对于较小的矩形,它的xy下标都应该减一。

那么答案也就显而易见了,直接用模板:

int query(int x, int y)//求出[1,1]~[x,y]的数值和
{
    int ans = 0;
    for (int i = x; i; i -= lowbit(i))
        for (int j = y; j; j -= lowbit(j))
            ans += a[i][j];
    return ans;
}
int main(){
    /*......*/
    int ans, l, b, r, t;
    cin >> l >> b >> r >> t;
    l++, b++, r++, t++;
    ans=query(r, t) - query(l - 1,) - (r, b - 1) + (l - 1, b - 1);//用{[1,1],[r,t]}(大矩形)减去{[1,1],[l - 1,t]},{[1,1],[r,b - 1]}(两个小矩形)再加上{[1,1],[l - 1,b - 1]}(重复运算的矩形)
}

CODE

#include <bits/stdc++.h>
using namespace std;
int a[2005][2005], n, q;
int lowbit(int x)
{
    return x & (-x);
}
void update(int x, int y, int d)
{
    for (int i = x; i <= n; i += lowbit(i))
        for (int j = y; j <= n; j += lowbit(j))
            a[i][j] += d;
}

int query(int x, int y)
{
    int ans = 0;
    for (int i = x; i; i -= lowbit(i))
        for (int j = y; j; j -= lowbit(j))
            ans += a[i][j];
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    while (cin >> q, q != 3)
    {
        int x, y, k, z;
        if (q == 0)
            cin >> n;
        if (q == 1)
        {
            cin >> x >> y >> k;
            update(x + 1, y + 1, k);
        }
        if (q == 2)
        {
            cin >> x >> y >> k >> z;
            x++, y++, k++, z++;
            cout << query(k, z) - query(x - 1, z) - query(k, y - 1) + query(x - 1, y - 1) << endl;
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值