您的位置:首页 > 其它

BZOJ4066 简单题

2016-05-24 21:05 232 查看

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

数据规模和约定

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

正解:kd-tree

解题报告:

   大概题意是给你一个二维的图,每次给一个点加上一个数,查询某个矩阵中的和,强制在线

kd-tree第二发题,又是一道模板水题 kd-tree最喜欢的强制在线。其实如果可以离线的话我可以用整体二分。

回到正题,一看数据范围n<=500000,操作数<=200000,显然500000*500000的空间是很令人愉快的,所以另辟蹊径。

   根据kd-tree思想,我们划分二维空间,搞出一棵神奇的二维二叉搜索树(kd-tree的本质),每次插入结点就直接按二叉搜索树的规则插入,查询也是按二叉搜索树的规则来查询。然而注意到这种做法在这道题是可以被卡的,比如说全挂在了一边,退化成链(变态出题人)

所以我们可以每插入5000个结点就重构一次树,把树的形态重新改变一下,这样就可以保证复杂度了。在BZOJ上跑得太慢了,只有rank50多。

具体实现看代码。

//It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#ifdef WIN32
#define OT "%I64d"
#else
#define OT "%lld"
#endif
using namespace std;
typedef long long LL;
const int MAXN = 200011;
const int MOD = 5000;
int n,m;
int ans;
int k1,k2,val;
int lx,ly,rx,ry;
int root;
int nowD;

struct node{
int d[2],Min[2],Max[2];
int sum,w;
int ch[2];
}t[MAXN];

inline int getint()
{
int w=0,q=0;
char c=getchar();
while((c<'0' || c>'9') && c!='-') c=getchar();
if (c=='-')  q=1, c=getchar();
while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
return q ? -w : w;
}

inline void update(int now){
t[now].sum=t[now].w;
for(int i=0;i<=1;i++) {
if(t[now].ch[i]) {
t[now].sum+=t[ t[now].ch[i] ].sum;
if(t[ t[now].ch[i] ].Min[0] < t[now].Min[0]) t[now].Min[0]=t[ t[now].ch[i] ].Min[0];
if(t[ t[now].ch[i] ].Max[0] > t[now].Max[0]) t[now].Max[0]=t[ t[now].ch[i] ].Max[0];
if(t[ t[now].ch[i] ].Min[1] < t[now].Min[1]) t[now].Min[1]=t[ t[now].ch[i] ].Min[1];
if(t[ t[now].ch[i] ].Max[1] > t[now].Max[1]) t[now].Max[1]=t[ t[now].ch[i] ].Max[1];
}
}
}

inline void kd_insert(int root,int D){
int direc=(t
.d[D]>t[root].d[D]);
if(t[root].ch[direc]) kd_insert(t[root].ch[direc],D^1);
else t[root].ch[direc]=n;
update(root);
}

inline void kd_query(int now){
if(t[now].d[0]>=lx && t[now].d[1]>=ly && t[now].d[0]<=rx && t[now].d[1]<=ry) ans+=t[now].w;
for(int i=0;i<=1;i++) {
if(t[now].ch[i]){
if(t[t[now].ch[i]].Min[0]<=rx&&t[t[now].ch[i]].Max[0]>=lx&&t[t[now].ch[i]].Min[1]<=ry&&t[t[now].ch[i]].Max[1]>=ly) {
if(t[t[now].ch[i]].Max[0]<=rx && t[t[now].ch[i]].Min[0]>=lx && t[t[now].ch[i]].Max[1]<=ry && t[t[now].ch[i]].Min[1]>=ly)   ans+=t[t[now].ch[i]].sum;
else kd_query(t[now].ch[i]);
}
}
}
}

inline bool cmp(node q,node qq){
if(q.d[nowD]==qq.d[nowD]) return q.d[nowD^1]<qq.d[nowD^1];
return q.d[nowD]<qq.d[nowD];
}

inline int rebuild(int l,int r,int D){
int mid=(l+r)/2; nowD=D;
nth_element(t+l+1,t+mid+1,t+r+1,cmp);
//t[mid].sum=t[mid].w;
t[mid].Min[0]=t[mid].Max[0]=t[mid].d[0]; t[mid].Min[1]=t[mid].Max[1]=t[mid].d[1];
if(l!=mid) t[mid].ch[0]=rebuild(l,mid-1,D^1);
if(mid!=r) t[mid].ch[1]=rebuild(mid+1,r,D^1);
update(mid);
return mid;
}

inline void solve(){
int ljh;  root=1;
while(1){
ljh=getint();
if(ljh==3) break;
else if(ljh==1) {
k1=getint();k2=getint();val=getint();
k1=k1^ans; k2=k2^ans; val=val^ans;
n++;  t
.Min[0]=t
.Max[0]=t
.d[0]=k1; t
.Min[1]=t
.Max[1]=t
.d[1]=k2; t
.w=t
.sum=val;
if(n>1){
if(n%MOD==0) {
for(int i=1;i<=n;i++) t[i].ch[0]=t[i].ch[1]=0;
root=rebuild(1,n,0);
}
else
kd_insert(root,0);
}
}
else {
lx=getint();ly=getint();rx=getint();ry=getint();
lx=lx^ans; ly=ly^ans; rx=rx^ans; ry=ry^ans;
ans=0;
if(n)
kd_query(root);
printf("%d\n",ans);
}
}
}

int main()
{
m=getint();  solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: