[BZOJ4066]简单题

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

命令参数限制内容
\(1\,x\,y\,A\)\(1\leqslant x,y\leqslant N\)\(A\)是正整数将格子\(x,y\)里的数字加上\(A\)
\(2\,x_1\,y_1\,x_2\,y_2\)\(1\leqslant x_1\leqslant x_2\leqslant N\\1\leqslant y_1\leqslant y_2\leqslant N\)输出\(x_1\,y_1\,x_2\,y_2\)这个矩形内的数字和
\(3\)终止程序

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

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

Sample Input
4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3

Sample Output
3
5

HINT
\(1\leqslant N\leqslant500000\),操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。


20M显然不能树套树……于是我们用一个简单的数据结构——KD-Tree

自信的写了一发,交上去TLE……一测数据发现极限数据跑了2m……

完全不会优化啊……还是%%%hzwer

定一个阀值,当KD-Tree插入操作达到这个阀值时,就暴力重构KD-Tree

然后就可以过了……

/*program from Wolfycz*/
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=2e5,V=1e4;
int T;
struct S1{
    #define ls(p) tree[p].ls
    #define rs(p) tree[p].rs
    struct node{
        int v[2],Max[2],Min[2];
        int ls,rs,type,val,sum;
        void insert(int type,int val){v[type]=Min[type]=Max[type]=val;}
        bool operator <(const node &tis)const{return v[T]<tis.v[T];}
    }tree[N+10];
    int root,tot;
    int L[2],R[2];
    void Add(int *a,int v){a[0]=a[1]=v;}
    void init(){Add(tree[0].Max,-inf),Add(tree[0].Min,inf);}
    void updata(int p){
        tree[p].Min[0]=min(tree[p].v[0],min(tree[ls(p)].Min[0],tree[rs(p)].Min[0]));
        tree[p].Min[1]=min(tree[p].v[1],min(tree[ls(p)].Min[1],tree[rs(p)].Min[1]));
        tree[p].Max[0]=max(tree[p].v[0],max(tree[ls(p)].Max[0],tree[rs(p)].Max[0]));
        tree[p].Max[1]=max(tree[p].v[1],max(tree[ls(p)].Max[1],tree[rs(p)].Max[1]));
    }
    int rebuild(int l,int r,int type){
        T=type;
        int mid=(l+r)>>1,p=mid;
        nth_element(tree+l,tree+mid,tree+r+1);
        tree[p].type=type,tree[p].sum=0;
        tree[p].ls=tree[p].rs=0;
        if (l<mid)  ls(p)=rebuild(l,mid-1,type^1);
        if (r>mid)  rs(p)=rebuild(mid+1,r,type^1);
        updata(p);
        tree[p].sum=tree[ls(p)].sum+tree[rs(p)].sum+tree[p].val;
        return p;
    }
    void Modify(int &p,int x,int y,int v){
        if (!p){
            p=++tot;
            tree[p].insert(0,x);
            tree[p].insert(1,y);
            tree[p].type=rand()&1;
            tree[p].val=tree[p].sum=v;
            return;
        }
        (tree[p].type?y:x)<tree[p].v[tree[p].type]?Modify(ls(p),x,y,v):Modify(rs(p),x,y,v);
        updata(p),tree[p].sum=tree[ls(p)].sum+tree[p].val+tree[rs(p)].sum;
    }
    int Query(int p){
        if (L[0] >tree[p].Max[0]||R[0] <tree[p].Min[0]||L[1] >tree[p].Max[1]||R[1] <tree[p].Min[1]) return 0;
        if (L[0]<=tree[p].Min[0]&&tree[p].Max[0]<=R[0]&&L[1]<=tree[p].Min[1]&&tree[p].Max[1]<=R[1]) return tree[p].sum;
        int res=0;
        if (L[0]<=tree[p].v[0]&&tree[p].v[0]<=R[0]&&L[1]<=tree[p].v[1]&&tree[p].v[1]<=R[1]) res=tree[p].val;
        res+=Query(ls(p))+Query(rs(p));
        return res;
    }
    int Query(int x1,int y1,int x2,int y2){
        L[0]=x1,R[0]=x2,L[1]=y1,R[1]=y2;
        return Query(root);
    }
}KDT;//KD-Tree
int main(){
    srand(time(0));
    int n=read(),cnt=0;
    KDT.init();
    for (int lastans=0;;){
        int type=read();
        if (type==1){
            cnt++;
            int x=read()^lastans,y=read()^lastans,v=read()^lastans;
            KDT.Modify(KDT.root,x,y,v);
            if (cnt%V==0)   KDT.root=KDT.rebuild(1,KDT.tot,0);
        }
        if (type==2){
            int x1=read()^lastans,y1=read()^lastans,x2=read()^lastans,y2=read()^lastans;
            printf("%d\n",lastans=KDT.Query(x1,y1,x2,y2));
        }
        if (type==3)    break;
    }
    return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/10284724.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值