bzoj 4066 简单题

你有一个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。
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案last_ans,初始时last_ans=0。

kd-tree练习题

#include<cstdio>
#include<string>
#include<algorithm>
#define ls t[o].s[0]
#define rs t[o].s[1]
using namespace std;
const int maxn=3e5+5;
int N,WD,rt,ans,top,cur,rub[maxn];
struct P{int d[2],w;}p[maxn];
struct T{int mn[2],mx[2],s[2],sz,sm;P tp;}t[maxn];
inline bool operator <(P a,P b) {return a.d[WD]<b.d[WD];}
inline int read() {
    int ret=0,f=1;char ch=getchar();
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') f=-f;
    for (; isdigit(ch); ch=getchar()) ret=ret*10+ch-48;
    return ret*f;
}
inline int newnode() {return top?rub[top--]:++cur;}
inline void pushup(int o) {
    for (int i=0; i<2; i++) {
        t[o].mn[i]=t[o].mx[i]=t[o].tp.d[i];
        if (ls) t[o].mn[i]=min(t[o].mn[i],t[ls].mn[i]),t[o].mx[i]=max(t[o].mx[i],t[ls].mx[i]);
        if (rs) t[o].mn[i]=min(t[o].mn[i],t[rs].mn[i]),t[o].mx[i]=max(t[o].mx[i],t[rs].mx[i]);
    }
    t[o].sz=1+t[ls].sz+t[rs].sz,t[o].sm=t[o].tp.w+t[ls].sm+t[rs].sm;
}
int build(int L,int R,int wd) {
    if (L>R) return 0;
    int mid=L+(R-L>>1),o=newnode();
    WD=wd,nth_element(p+L,p+mid,p+R+1),t[o].tp=p[mid];
    ls=build(L,mid-1,wd^1),rs=build(mid+1,R,wd^1);
    pushup(o);return o;
}
void pia(int o,int num) {
    if (ls) pia(ls,num);
    p[num+t[ls].sz+1]=t[o].tp,rub[++top]=o;
    if (rs) pia(rs,num+t[ls].sz+1);
}
inline void check(int &o,int wd) {
    if (0.75*t[o].sz<t[ls].sz||0.75*t[o].sz<t[rs].sz) pia(o,0),o=build(1,t[o].sz,wd);
}
void Insert(P tmp,int &o,int wd) {
    if (!o) {o=newnode(),t[o].tp=tmp,ls=rs=0,pushup(o);return;}
    if (t[o].tp.d[wd]>=tmp.d[wd]) Insert(tmp,ls,wd^1);
    else Insert(tmp,rs,wd^1);
    pushup(o),check(o,wd);
}
inline bool in(int x,int y,int l,int r,int X,int Y,int L,int R) {return x>=X&&l<=L&&y>=Y&&r<=R;}
inline bool out(int x,int y,int l,int r,int X,int Y,int L,int R) {return x>L||l<X||y>R||r<Y;}
int Query(int x,int y,int l,int r,int o) {
    if (!o) return 0;
    if (in(t[o].mn[0],t[o].mn[1],t[o].mx[0],t[o].mx[1],x,y,l,r)) return t[o].sm;
    if (out(t[o].mn[0],t[o].mn[1],t[o].mx[0],t[o].mx[1],x,y,l,r)) return 0;
    int ret=0;
    if (in(t[o].tp.d[0],t[o].tp.d[1],t[o].tp.d[0],t[o].tp.d[1],x,y,l,r)) ret+=t[o].tp.w;
    return Query(x,y,l,r,ls)+Query(x,y,l,r,rs)+ret;
}
int main() {
    N=read();
    P tmp;
    for (int opt=read(),x,y,l,r; opt^3; opt=read())
        if (opt==1) {
            tmp.d[0]=read()^ans,tmp.d[1]=read()^ans,tmp.w=read()^ans;
            Insert(tmp,rt,0);
        } else {
            x=read()^ans,y=read()^ans,l=read()^ans,r=read()^ans;
            printf("%d\n",ans=Query(x,y,l,r,rt));
        }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值