poj 1195 Mobile phones

题目链接如下:

1195 -- Mobile phones

很有意思的一个二维线段树。

一开始我想,这么简单,把二维拉到一维不就行了吗,结果就是发现,在求那个长方形的区间和的时候无从下手。

然后用二维写。

一个二维数组来维护和,每个行代表的是一个线段树,每一列也构成线段树,而数组的位置代表的是行是[l1,r1],列是[l2,r2]的长方形的和。

那么update的时候:

我们先用二分限定x区间到输入的x的位置,再用二分限定y的位置,进行单个点上的更新就好了。这里我们要注意的是其他的节点的总和的更新,我们在单个线段树的时候一般是要pushup,这里也差不多,我们要对[l1,r1],[l2,r2]的每一个长方形进行更新。

query的修改也如出一辙。

具体代码如下所示:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
#include<queue>
#include<string>
#include<cmath>
#include<climits>

using namespace std;
const int MAXN=1050;
int n,val,X1,Y1,X2,Y2,tmp_x,tmp_y;
int sum[MAXN*3][MAXN*3];

void update_y(int x,int l,int r,int rtx,int rty){
    if (l==r){
        if (x!=-1){
            sum[rtx][rty]+=val;
        } else{
            sum[rtx][rty]=sum[rtx<<1][rty]+sum[rtx<<1|1][rty];
        }
        return;
    }
    int mid=(l+r)>>1;
    if (tmp_y<=mid){
        update_y(x,l,mid,rtx,rty<<1);
    } else{
        update_y(x,mid+1,r,rtx,rty<<1|1);
    }
    sum[rtx][rty]=sum[rtx][rty<<1]+sum[rtx][rty<<1|1];
}

void update_x(int l,int r,int rtx){
    if (l==r){
        update_y(l,1,n,rtx,1);
        return;
    }
    int mid=(l+r)>>1;
    if (tmp_x<=mid){
        update_x(l,mid,rtx<<1);
    } else{
        update_x(mid+1,r,rtx<<1|1);
    }
    update_y(-1,1,n,rtx,1);
}

long long query_y(int l,int r,int rtx,int rty){
    if (Y1<=l && Y2>=r){
        return sum[rtx][rty];
    }
    long long ans=0;
    int mid=(l+r)>>1;
    if (Y1<=mid){
        ans+= query_y(l,mid,rtx,rty<<1);
    }
    if (Y2>mid){
        ans+= query_y(mid+1,r,rtx,rty<<1|1);
    }
    return ans;
}

long long query_x(int l,int r,int rtx){
    if (X1<=l && X2>=r){
        return query_y(1,n,rtx,1);
    }
    long long ans=0;
    int mid=(l+r)>>1;
    if (X1<=mid){
        ans+=query_x(l,mid,rtx<<1);
    }
    if (X2>mid){
        ans+=query_x(mid+1,r,rtx<<1|1);
    }
    return ans;
}

int main(){
    int instr;
    while (scanf("%d %d",&instr,&n)!=EOF){
        memset(sum,0, sizeof(sum));
        while (scanf("%d",&instr)){
            if (instr==3) break;
            else if (instr==1){
                scanf("%d %d %d",&tmp_x,&tmp_y,&val);
                tmp_x++,tmp_y++;
                update_x(1,n,1);
            }else{
                scanf("%d %d %d %d",&X1,&Y1,&X2,&Y2);
                X1++,X2++,Y1++,Y2++;
                printf("%lld\n", query_x(1,n,1));
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值