Tyvj1474 打鼹鼠

Description

在这个“打鼹鼠”的游戏中,鼹鼠会不时地从洞中钻出来,不过不会从洞口钻进去(鼹鼠真胆大……)。洞口都在
一个大小为n(n<=1024)的正方形中。这个正方形在一个平面直角坐标系中,左下角为(0,0),右上角为(n-1,n-1)。
洞口所在的位置都是整点,就是横纵坐标都为整数的点。而SuperBrother也不时地会想知道某一个范围的鼹鼠总数
。这就是你的任务。

Input

每个输入文件有多行。
第一行,一个数n,表示鼹鼠的范围。
以后每一行开头都有一个数m,表示不同的操作:
m=1,那么后面跟着3个数x,y,k(0<=x,y<n),表示在点(x,y)处新出现了k只鼹鼠;
m=2,那么后面跟着4个数x1,y1,x2,y2(0<=x1<=x2<n,0<=y1<=y2<n),表示询问矩形(x1,y1)-(x2,y2)内的鼹鼠数量;
m=3,表示老师来了,不能玩了。保证这个数会在输入的最后一行。
询问数不会超过10000,鼹鼠数不会超过maxlongint。

Output

对于每个m=2,输出一行数,这行数只有一个数,即所询问的区域内鼹鼠的个数。

Sample Input

4
1 2 2 5
2 0 0 2 3
3

Sample Output

5

乍一看这个题目,是不是很像线段树操作,欸,这个二维平面怎么线段树啊


让我们来想一想,一颗线段树维护x轴,另一颗维护y轴,


那线段树岂不是要嵌套,那外层的线段树的每一个节点都代表1个x坐标,那么每个节点都得保存一颗线段树,那颗内层的线段树就保存y坐标;

这种数据结构就叫做二维线段树

修改操作就稍微麻烦一点了


要先在外层线段树中查找x坐标,再到当前x坐标保存的y坐标的线段树中去找,进行修改



提示:外层线段树是不能进行修改的!!!

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a,b,c,d,n,m,ans;
void read(int &x) {
    char ch; bool ok;
    for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
}
struct oo
{
    int a,b;
    struct o{int a,b,num;}y[3025];
    void build(int now,int l,int r)
    {
        y[now].a=l,y[now].b=r;
        if(l==r)return ;
        build(now<<1,l,l+r>>1);
        build(now<<1|1,(l+r>>1)+1,r);
    }
    void change(int now,int r,int num)
    {
        y[now].num+=num;
        if(y[now].a==y[now].b)return ;
        int mid=y[now].a+y[now].b>>1;
        if(r<=mid)change(now<<1,r,num);
        else change(now<<1|1,r,num);
    }
    void get(int now,int b1,int b2)
    {
        if(b1<=y[now].a&&b2>=y[now].b)
            ans+=y[now].num;
        else
        {
            int mid=y[now].a+y[now].b>>1;
            if(b1<=mid)get(now<<1,b1,b2);
            if(b2>mid)get(now<<1|1,b1,b2);
        }
}
}x[3025];
void build(int now,int l,int r)
{
    x[now].a=l,x[now].b=r;
    x[now].build(1,0,n);
    if(l==r)return ;
    build(now<<1,l,l+r>>1);
    build(now<<1|1,(l+r>>1)+1,r);
}
void change(int now,int l,int r,int num)
{
    x[now].change(1,r,num);
    if(x[now].a==x[now].b)return ;
    int mid=x[now].a+x[now].b>>1;
    if(l<=mid)change(now<<1,l,r,num);
    else change(now<<1|1,l,r,num);
}
void get(int now,int a1,int a2,int b1,int b2)
{
    if(a1<=x[now].a&&a2>=x[now].b)
        x[now].get(1,b1,b2);
    else
    {
        int mid=x[now].a+x[now].b>>1;
        if(a1<=mid)get(now<<1,a1,a2,b1,b2);
        if(a2>mid)get(now<<1|1,a1,a2,b1,b2);
    }
}
int main()
{
    read(n);
    build(1,0,n);
    while(1)
    {   
        read(m);
        if(m==3)return 0;
        if(m==1)
        {
            read(a),read(b),read(c);
            change(1,a,b,c);
        }
        if(m==2)
        {
            read(a),read(b),read(c);read(d);
            get(1,a,c,b,d);
            printf("%d\n",ans);
            ans=0;
        }
    }
}
祝大家早日AC!!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值