bzoj 2683: 简单题 k-d tree

Description

你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

命令
参数限制
内容
1 x y A
1<=x,y<=N,A是正整数
将格子x,y里的数字加上A
2 x1 y1 x2 y2
1<=x1<= x2<=N
1<=y1<= y2<=N
输出x1 y1 x2 y2这个矩形内的数字和
3

终止程序
Input

输入文件第一行一个正整数N。
接下来每行一个操作。

Output

对于每个2操作,输出一个对应的答案。

Sample Input

4

1 2 3 3

2 1 1 3 3

1 2 2 2

2 2 2 3 4

3

Sample Output

3

5

HINT

1<=N<=500000,操作数不超过200000个,内存限制20M。

对于100%的数据,操作1中的A不超过2000。

分析:一道模版的k-d tree,结果空间卡得太紧了,反正洛谷过不了,于是就跑到bzoj上交。
k-d tree反正每次就是把宽度最大的切一半,这题要动态开点,我觉得不动态也能过。

代码:

/**************************************************************
    Problem: 2683
    User: beginend
    Language: C++
    Result: Accepted
    Time:45488 ms
    Memory:71604 kb
****************************************************************/

#include <iostream>
#include <cstdio>

using namespace std;

struct node{
    int s,lc,rc;
}t[6000001];

int n,i,cnt;
int op,l,r,x,y,w,last_ans,root;


void change(int &p,int x,int y,int k,int ll,int rr,int xx,int yy)
{
    if (p==0)
    {
        cnt++;
        p=cnt;
    }
    if ((x==ll) && (x==rr) && (y==xx) && (y==yy))
    {
        t[p].s+=k;
        return;
    }
    if (yy-xx>rr-ll)
    {
        int mid=(xx+yy)/2;
        if (y<=mid) change(t[p].lc,x,y,k,ll,rr,xx,mid);
               else change(t[p].rc,x,y,k,ll,rr,mid+1,yy);
        t[p].s=t[t[p].lc].s+t[t[p].rc].s;       
    }
    else
    {
        int mid=(ll+rr)/2;
        if (x<=mid) change(t[p].lc,x,y,k,ll,mid,xx,yy);
               else change(t[p].rc,x,y,k,mid+1,rr,xx,yy);
        t[p].s=t[t[p].lc].s+t[t[p].rc].s;       
    }
}

int getsum(int p,int l,int r,int x,int y,int ll,int rr,int xx,int yy)
{
    if (p==0) return 0;
    if ((ll==l) && (rr==r) && (xx==x) && (yy==y)) return t[p].s;
    if (yy-xx>rr-ll)
    {
        int mid=(xx+yy)/2;
        if (y<=mid) return getsum(t[p].lc,l,r,x,y,ll,rr,xx,mid);
        else
        {
            if (x>mid) return getsum(t[p].rc,l,r,x,y,ll,rr,mid+1,yy);
            else
               return getsum(t[p].lc,l,r,x,mid,ll,rr,xx,mid)
                        +getsum(t[p].rc,l,r,mid+1,y,ll,rr,mid+1,yy);
        }
    }
    else
    {
        int mid=(ll+rr)/2;
        if (r<=mid) return getsum(t[p].lc,l,r,x,y,ll,mid,xx,yy);
        else
        {
            if (l>mid) return getsum(t[p].rc,l,r,x,y,mid+1,rr,xx,yy);
            else
               return getsum(t[p].lc,l,mid,x,y,ll,mid,xx,yy)
                        +getsum(t[p].rc,mid+1,r,x,y,mid+1,rr,xx,yy);
        }
    }
}

int main()
{
    scanf("%d",&n);
    scanf("%d",&op);
    last_ans=0;
    while (op!=3)
    {           
        if (op==1)
        {
            scanf("%d%d%d",&x,&y,&w);
            //x^=last_ans;
            //y^=last_ans;
            //w^=last_ans;
            change(root,x,y,w,1,n,1,n);
        }
        else
        {
            scanf("%d%d%d%d",&l,&r,&x,&y);
            //l^=last_ans;
            //r^=last_ans;
            //x^=last_ans;
            //y^=last_ans;
            last_ans=getsum(root,l,x,r,y,1,n,1,n);
            printf("%d\n",last_ans);
        }
        scanf("%d",&op);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值