简单题

题目

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

1 x y A 1\le x,y\le N1≤x,y≤N,A是正整数。将格子x,y里的数字加上AA
2 x1 y1 x2 y2 1 \le x_1 \le x_2 \le N1≤x
1

≤x
2

≤N,1 \le y_1\le y_2 \le N1≤y
1

≤y
2

≤N。输出x_1, y_1, x_2, y_2x
1

,y
1

,x
2

,y
2

这个矩形内的数字和
3 无 终止程序
输入格式
输入文件第一行一个正整数N。

接下来每行一个操作。每条命令除第一个数字之外,均要异或上一次输出的答案last_ans,初始时last_ans=0。

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

输入输出样例
输入 #1 复制
4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3
输出 #1 复制
3
5
说明/提示
1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

思路

KD-tree模板题
把每个插入操作看成一个点
如果插入导致不平衡,就像替罪羊树那样拍扁重构。
每个节点记录子树内横纵坐标的最大值
查询就比较显然了

代码

#include<bits/stdc++.h>
using namespace std;
int read() {
    int q=0,w=1;char ch=' ';
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') w=-1,ch=getchar();
    while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
    return q*w;
}
const int N=200005;
struct yjy{int x[2],w;}p[N];
struct node{int mi[2],mx[2],sum,ls,rs,sz;yjy tp;}tr[N];
int n,ans,rt,WD,top,cur,rub[N];
int operator < (yjy a,yjy b) {return a.x[WD]<b.x[WD];}
int newnode() {
    if(top) return rub[top--];
    else return ++cur;
}
void up(int k) {
    int l=tr[k].ls,r=tr[k].rs;
    for(int i=0;i<=1;++i) {
        tr[k].mi[i]=tr[k].mx[i]=tr[k].tp.x[i];
        if(l) tr[k].mi[i]=mcheck_1(tr[k].mi[i],tr[l].mi[i]);
        if(r) tr[k].mi[i]=mcheck_1(tr[k].mi[i],tr[r].mi[i]);
        if(l) tr[k].mx[i]=max(tr[k].mx[i],tr[l].mx[i]);
        if(r) tr[k].mx[i]=max(tr[k].mx[i],tr[r].mx[i]);
    }
    tr[k].sum=tr[l].sum+tr[r].sum+tr[k].tp.w,tr[k].sz=tr[l].sz+tr[r].sz+1;
}
int build(int l,int r,int wd) {
    if(l>r) return 0;
    int mid=(l+r)>>1,k=newnode();
    WD=wd,nth_element(p+l,p+mid,p+r+1),tr[k].tp=p[mid];
    tr[k].ls=build(l,mid-1,wd^1),tr[k].rs=build(mid+1,r,wd^1);
    up(k);return k;
}
void pia(int k,int num) {
    if(tr[k].ls) pia(tr[k].ls,num);
    p[tr[tr[k].ls].sz+num+1]=tr[k].tp,rub[++top]=k;
    if(tr[k].rs) pia(tr[k].rs,num+tr[tr[k].ls].sz+1);
}
void check(int &k,int wd) {
    if(tr[k].sz*0.75<tr[tr[k].ls].sz||tr[k].sz*0.75<tr[tr[k].rs].sz)
        pia(k,0),k=build(1,tr[k].sz,wd);
}
void ins(int &k,yjy tmp,int wd) {
    if(!k) {k=newnode(),tr[k].ls=tr[k].rs=0,tr[k].tp=tmp,up(k);return;}
    if(tmp.x[wd]<=tr[k].tp.x[wd]) ins(tr[k].ls,tmp,wd^1);
    else ins(tr[k].rs,tmp,wd^1);
    up(k),check(k,wd);
}
int check_1(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2) {
    return (X1>=x1&&X2<=x2&&Y1>=y1&&Y2<=y2);
}
int check_2(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2) {
    return (x1>X2||x2<X1||y1>Y2||y2<Y1);
}
int query(int k,int x1,int y1,int x2,int y2) {
    if(!k) return 0;
    int re=0;
    if(check_1(x1,y1,x2,y2,tr[k].mi[0],tr[k].mi[1],tr[k].mx[0],tr[k].mx[1])) return tr[k].sum;
    if(check_2(x1,y1,x2,y2,tr[k].mi[0],tr[k].mi[1],tr[k].mx[0],tr[k].mx[1])) return 0;
    if(check_1(x1,y1,x2,y2,tr[k].tp.x[0],tr[k].tp.x[1],tr[k].tp.x[0],tr[k].tp.x[1]))
        re+=tr[k].tp.w;
    re+=query(tr[k].ls,x1,y1,x2,y2)+query(tr[k].rs,x1,y1,x2,y2);
    return re;
}
int main()
{
    int bj,x1,y1,x2,y2;
    n=read();
    while(1)
	{
        bj=read(); if(bj==3) break;
        if(bj==1) ins(rt,(yjy){read()^ans,read()^ans,read()^ans},0);
        else
		{
            x1=read()^ans,y1=read()^ans,x2=read()^ans,y2=read()^ans;
            ans=query(rt,x1,y1,x2,y2),printf("%d\n",ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值