BZOJ4066: 简单题

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。
接下来每行一个操作。每条命令除第一个数字之外,
均要异或上一次输出的答案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<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

样例解释见OJ2683
新加数据一组,但未重测----2015.05.24

 

隔壁AKC一眼CDQ发现是在线又一眼树套树发现MLE了。。

实在不是很会搞,分割平面那就KD-tree走一波

至于加值,那就是插点,查找就类似于线段树维护下子树和不行递归找

然后T掉了:多次加点使树的结构失衡,退化为平方级算法

那就暴力重构,每到一定范围就像替罪羊树一样强行拆开重构

//MT_LI
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
struct KDT{
    int lc,rc,s,sum;
    int mn[2],mx[2],d[2];
}tr[500010];
void update(int x)
{
    int lc=tr[x].lc,rc=tr[x].rc;
    if(lc)
    {
        tr[x].mn[0]=min(tr[x].mn[0],tr[lc].mn[0]);
        tr[x].mn[1]=min(tr[x].mn[1],tr[lc].mn[1]);
        tr[x].mx[0]=max(tr[x].mx[0],tr[lc].mx[0]);
        tr[x].mx[1]=max(tr[x].mx[1],tr[lc].mx[1]);
        tr[x].sum+=tr[lc].sum;
    }
    if(rc)
    {
        tr[x].mn[0]=min(tr[x].mn[0],tr[rc].mn[0]);
        tr[x].mn[1]=min(tr[x].mn[1],tr[rc].mn[1]);
        tr[x].mx[0]=max(tr[x].mx[0],tr[rc].mx[0]);
        tr[x].mx[1]=max(tr[x].mx[1],tr[rc].mx[1]);
        tr[x].sum+=tr[rc].sum;
    }
}
int cmpd,root;
bool cmp(KDT a,KDT b){return a.d[cmpd]<b.d[cmpd] || a.d[cmpd]==b.d[cmpd]&&a.d[cmpd^1]<b.d[cmpd^1];}
void ins(int now)
{
    int p=root;
    while(1)
    {
        if(tr[p].mx[0]<tr[now].mx[0])tr[p].mx[0]=tr[now].mx[0];
        if(tr[p].mx[1]<tr[now].mx[1])tr[p].mx[1]=tr[now].mx[1];
        if(tr[p].mn[0]>tr[now].mn[0])tr[p].mn[0]=tr[now].mn[0];
        if(tr[p].mn[1]>tr[now].mn[1])tr[p].mn[1]=tr[now].mn[1];
        tr[p].sum+=tr[now].sum;
        if(tr[now].d[cmpd]<tr[p].d[cmpd])
        {
            if(tr[p].lc==0){tr[p].lc=now;return ;}
            else p=tr[p].lc;
        }
        else
        {
            if(tr[p].rc==0){tr[p].rc=now;return ;}
            else p=tr[p].rc;
        }
        cmpd^=1;
    }
}
int find(int x,int x1,int y1,int x2,int y2)
{
    if(tr[x].mn[0]>x2||tr[x].mn[1]>y2||tr[x].mx[0]<x1||tr[x].mx[1]<y1)return 0;
    if(tr[x].mx[0]<=x2&&tr[x].mx[1]<=y2&&tr[x].mn[0]>=x1&&tr[x].mn[1]>=y1)return tr[x].sum;
    int tot=0;
    if(tr[x].d[0]>=x1&&tr[x].d[1]>=y1&&tr[x].d[0]<=x2&&tr[x].d[1]<=y2)tot=tr[x].s;
    if(tr[x].lc)tot+=find(tr[x].lc,x1,y1,x2,y2);
    if(tr[x].rc)tot+=find(tr[x].rc,x1,y1,x2,y2);
    return tot;
}
int rebuild(int l,int r,int d)
{
    int mid=(l+r)/2,now;
    now=mid;cmpd=d;
    nth_element(tr+l,tr+mid,tr+r+1,cmp);
    tr[now].mx[0]=tr[now].mn[0]=tr[now].d[0];
    tr[now].mx[1]=tr[now].mn[1]=tr[now].d[1];
    tr[now].sum=tr[now].s;
    if(l<mid)tr[now].lc=rebuild(l,mid-1,d^1);
    if(mid<r)tr[now].rc=rebuild(mid+1,r,d^1);
    update(now);
    return now;
}
int ans=0;
int main()
{
    int n;int cnt=0;
    scanf("%d",&n);root=0;
    while(1)
    {
        int op;
        scanf("%d",&op);
        if(op==3)break;
        if(op==1)
        {
            ++cnt;
            scanf("%d%d%d",&tr[cnt].d[0],&tr[cnt].d[1],&tr[cnt].s);
            tr[cnt].d[0]^=ans;tr[cnt].d[1]^=ans;tr[cnt].s^=ans;
            tr[cnt].mx[0]=tr[cnt].mn[0]=tr[cnt].d[0];
            tr[cnt].mx[1]=tr[cnt].mn[1]=tr[cnt].d[1];
            tr[cnt].sum=tr[cnt].s;
            if(cnt%10000==0)
            {
                for(int i=1;i<=cnt;i++)tr[i].lc=tr[i].rc=0;
                root=rebuild(1,cnt,0);
                continue;
            }
            if(root==0)root=cnt;
            else cmpd=0,ins(cnt);
        }
        else
        {
            int x1,x2,y1,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            x1^=ans;x2^=ans;y1^=ans;y2^=ans;
            ans=find(root,x1,y1,x2,y2);
            printf("%d\n",ans);            
        }
    }
    return 0;
}

 

posted @ 2018-10-15 16:20  MT_LI  阅读(166)  评论(0编辑  收藏  举报