题意:单点更新,大矩阵(\(n*n,n≤10^5\))求和

二维的KD树能使最坏情况不高于\(O(N\sqrt{N})\)

核心在于query时判断当前子树维护的区间是否有交集/当前子节点是否在块中,然后暴力....

然后跑30s的KD树...

维护size的重构方法不知为何T了,借鉴了hzwer的按数目重构

一个微小的工作是如果更新时点相同那就直接合并,不要另开(虽然还是可以轻易地被卡)

T了三天三夜的题总算告一段落了

#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
using namespace std;
const int MAXN = 2e5+11;
const int INF = 0x7fffffff;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int D;
struct Point{
int x[2],val;
bool operator < (const Point &rhs) const{
return x[D]<rhs.x[D];
}
};
//struct REC{
// int x[2],val;
// bool operator < (const REC &rhs) const{
// return x[D]<rhs.x[D];
// }
//}rec[MAXN];
struct KD{
int son[MAXN][2],lx[MAXN][2],rx[MAXN][2];
int size[MAXN];
ll sum[MAXN];
Point p[MAXN];
int root,tot;
void pu(int o){
int lc=son[o][0],rc=son[o][1];
rep(i,0,1){
lx[o][i]=rx[o][i]=p[o].x[i];
if(lc){
if(lx[lc][i]<lx[o][i]) lx[o][i]=lx[lc][i];
if(rx[lc][i]>rx[o][i]) rx[o][i]=rx[lc][i];
}
if(rc){
if(lx[rc][i]<lx[o][i]) lx[o][i]=lx[rc][i];
if(rx[rc][i]>rx[o][i]) rx[o][i]=rx[rc][i];
}
}
sum[o]=p[o].val+sum[lc]+sum[rc];
size[o]=1+size[lc]+size[rc];
}
void init(){
root=tot=D=0;
}
bool ok(int o){
int lc=son[o][0],rc=son[o][1];
int ls=size[lc]<<2;
int rs=size[rc]<<2;
int sz=size[o]<<1|1;
return ls<=sz&&rs<=sz;
}
void insert(int &o,int now,int x,int y,int v){
if(!o){
o=++tot;
p[o].x[0]=lx[o][0]=rx[o][0]=x;
p[o].x[1]=lx[o][1]=rx[o][1]=y;
p[o].val=sum[o]=v;size[o]=1;
son[o][0]=son[o][1]=0;
return;
}else if(p[o].x[0]==x&&p[o].x[1]==y){
p[o].val+=v;sum[o]+=v;
return;
}else if(now==0){
if(x<p[o].x[0]) insert(son[o][0],1,x,y,v);
else insert(son[o][1],1,x,y,v);
}else{
if(y<p[o].x[1]) insert(son[o][0],0,x,y,v);
else insert(son[o][1],0,x,y,v);
}
pu(o);
}
bool inside(int x_1,int y_1,int x_2,int y_2,int X1,int Y1,int X2,int Y2){
return x_1<=X1&&X2<=x_2&&y_1<=Y1&&Y2<=y_2;
}
bool outside(int x_1,int y_1,int x_2,int y_2,int X1,int Y1,int X2,int Y2){
return x_1>X2||x_2<X1||y_1>Y2||y_2<Y1;
}
ll query(int o,int x_1,int y_1,int x_2,int y_2){
if(!o) return 0;
#define RECT lx[o][0],lx[o][1],rx[o][0],rx[o][1]
#define POT p[o].x[0],p[o].x[1],p[o].x[0],p[o].x[1]
if(inside(x_1,y_1,x_2,y_2,RECT)) return sum[o];
if(outside(x_1,y_1,x_2,y_2,RECT)) return 0;
ll res=0;
if(inside(x_1,y_1,x_2,y_2,POT)) res=p[o].val;
return res+query(son[o][0],x_1,y_1,x_2,y_2)+query(son[o][1],x_1,y_1,x_2,y_2);
}
int rebuild(int now,int l,int r){
int mid=l+r>>1; son[mid][0]=son[mid][1]=0;
D=now; nth_element(p+l,p+mid,p+r+1);
// p[mid].x[0]=rec[mid].x[0];p[mid].x[1]=rec[mid].x[1];
// val[mid]=sum[mid]=rec[mid].val;size[mid]=1;
sum[mid]=p[mid].val; size[mid]=1;
lx[mid][0]=rx[mid][0]=p[mid].x[0];
lx[mid][1]=rx[mid][1]=p[mid].x[1];
if(l<mid) son[mid][0]=rebuild(now^1,l,mid-1);
if(r>mid) son[mid][1]=rebuild(now^1,mid+1,r);
pu(mid);
return mid;
}
void recycle(){
root=rebuild(0,1,tot);
}
}kd;
int main(){
ll n,lastans=0;
while(cin>>n){
kd.init();
int m=10000;
while(1){
int op=read();
if(op==3) break;
else if(op==1){
int x=read()^lastans;
int y=read()^lastans;
int v=read()^lastans;
kd.insert(kd.root,0,x,y,v);
if(kd.tot==m) kd.recycle(),m+=10000;
}else{
int x_1=read()^lastans;
int y_1=read()^lastans;
int x_2=read()^lastans;
int y_2=read()^lastans;
lastans=kd.query(kd.root,x_1,y_1,x_2,y_2);
println(lastans);
}
}
}
return 0;
}

顺便贴上按size平衡因子维护的版本(TLE,不打算改了)

#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
using namespace std;
const int MAXN = 2e5+11;
const int INF = 0x7fffffff;
typedef long long ll;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int D;
struct Point{
int x[2],val;
bool operator < (const Point &rhs) const{
return x[D]<rhs.x[D];
}
}p[MAXN];
struct KD{
int son[MAXN][2],lx[MAXN][2],rx[MAXN][2];
int size[MAXN];
ll sum[MAXN];
int root,tot;
struct REC{
int id;
bool operator < (const REC &rhs) const{
return p[id]<p[rhs.id];
}
}rec[MAXN];int cnt;
void dfs(int o){
if(!o) return;
dfs(son[o][0]);
rec[++cnt].id=o;
dfs(son[o][1]);
}
void pu(int o){
int lc=son[o][0],rc=son[o][1];
rep(i,0,1){
lx[o][i]=rx[o][i]=p[o].x[i];
if(lc){
if(lx[lc][i]<lx[o][i]) lx[o][i]=lx[lc][i];
if(rx[lc][i]>rx[o][i]) rx[o][i]=rx[lc][i];
}
if(rc){
if(lx[rc][i]<lx[o][i]) lx[o][i]=lx[rc][i];
if(rx[rc][i]>rx[o][i]) rx[o][i]=rx[rc][i];
}
}
sum[o]=p[o].val+sum[lc]+sum[rc];
size[o]=1+size[lc]+size[rc];
}
void init(){
root=tot=D=0;
}
bool ok(int o){
int lc=son[o][0],rc=son[o][1];
int ls=size[lc]<<2;
int rs=size[rc]<<2;
int sz=size[o]<<1|1;
return ls<=sz&&rs<=sz;
}
void insert(int &o,int now,int x,int y,int v){
if(!o){
o=++tot;
p[o].x[0]=lx[o][0]=rx[o][0]=x;
p[o].x[1]=lx[o][1]=rx[o][1]=y;
p[o].val=sum[o]=v;size[o]=1;
son[o][0]=son[o][1]=0;
return;
}else if(p[o].x[0]==x&&p[o].x[1]==y){
p[o].val+=v;sum[o]+=v;
return;
}else if(now==0){
if(x<p[o].x[0]) insert(son[o][0],1,x,y,v);
else insert(son[o][1],1,x,y,v);
}else{
if(y<p[o].x[1]) insert(son[o][0],0,x,y,v);
else insert(son[o][1],0,x,y,v);
}
pu(o);
if(size[o]>1000&&!ok(o)) rebuild(o);
}
bool inside(int x_1,int y_1,int x_2,int y_2,int X1,int Y1,int X2,int Y2){
return x_1<=X1&&X2<=x_2&&y_1<=Y1&&Y2<=y_2;
}
bool outside(int x_1,int y_1,int x_2,int y_2,int X1,int Y1,int X2,int Y2){
return x_1>X2||x_2<X1||y_1>Y2||y_2<Y1;
}
ll query(int o,int x_1,int y_1,int x_2,int y_2){
if(!o) return 0;
#define RECT lx[o][0],lx[o][1],rx[o][0],rx[o][1]
#define POT p[o].x[0],p[o].x[1],p[o].x[0],p[o].x[1]
if(inside(x_1,y_1,x_2,y_2,RECT)) return sum[o];
if(outside(x_1,y_1,x_2,y_2,RECT)) return 0;
ll res=0;
if(inside(x_1,y_1,x_2,y_2,POT)) res=p[o].val;
return res+query(son[o][0],x_1,y_1,x_2,y_2)+query(son[o][1],x_1,y_1,x_2,y_2);
}
int rebuild(int now,int l,int r){
int mid=l+r>>1;
D=now; nth_element(rec+l,rec+mid,rec+r+1);
int o=rec[mid].id;
sum[o]=p[o].val; size[o]=1;
son[o][0]=son[o][1]=0;
lx[o][0]=rx[o][0]=p[o].x[0];
lx[o][1]=rx[o][1]=p[o].x[1];
if(l<mid) son[o][0]=rebuild(now^1,l,mid-1);
if(r>mid) son[o][1]=rebuild(now^1,mid+1,r);
pu(o);
return o;
}
void rebuild(int &o){
cnt=0;
dfs(o);
o=rebuild(0,1,cnt);
}
}kd;
int main(){
ll n,lastans=0;
while(cin>>n){
kd.init();
while(1){
int op=read();
if(op==3) break;
else if(op==1){
int x=read()^lastans;
int y=read()^lastans;
int v=read()^lastans;
kd.insert(kd.root,0,x,y,v);
}else{
int x_1=read()^lastans;
int y_1=read()^lastans;
int x_2=read()^lastans;
int y_2=read()^lastans;
lastans=kd.query(kd.root,x_1,y_1,x_2,y_2);
println(lastans);
}
}
}
return 0;
}

BZOJ - 4066 KD树 范围计数 暴力重构的更多相关文章

  1. BZOJ - 3489 KD树 范围计数 空间思维转换

    题意:给定数列\(a[1...n]\),\(Q\)次查询\([L,R]\)中只出现一次的最大值 这道题的做法比较劲.. 对每个元素构造三维空间的点\((i,pre[i],next[i])\),查询\( ...

  2. bzoj 3489: A simple rmq problem k-d树思想大暴力

    3489: A simple rmq problem Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 551  Solved: 170[Submit][ ...

  3. BZOJ 1211: [HNOI2004]树的计数( 组合数学 )

    知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! -------------------------------------- ...

  4. bzoj 1211: [HNOI2004]树的计数 -- purfer序列

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MB Description 一个有n个结点的树,设它的结点分别为v1, v2, ...

  5. BZOJ - 2648 KD树 最近点查询

    省赛后躺尸几天又回来更新了,内容是说好的KD树.. 具体操作从代码中感受一下 感觉已经把KD树尽量封装好了(虽然全局的D看着极不顺眼) 需要注意的是估值函数的判断条件 #include<bits ...

  6. 数据结构(平衡树,树分治,暴力重构):WC 2014 紫荆花之恋

    [题目描述] 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这棵大树实际上是一个带权 ...

  7. BZOJ 1211 HNOI2004 树的计数 Prufer序列

    题目大意:给定一棵树中全部点的度数,求有多少种可能的树 Prufer序列.详细參考[HNOI2008]明明的烦恼 直接乘会爆long long,所以先把每一个数分解质因数.把质因数的次数相加相减.然后 ...

  8. bzoj 3244: [Noi2013]树的计数

    Description 我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的DFS序以及BFS序.两棵不同的树的DFS序有可能相同,并且它们的BFS序也有可能相同, ...

  9. BZOJ 1211[HNOI2004]树的计数 - prufer数列

    描述 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi) ...

随机推荐

  1. ROS导航包的介绍

    博客转载自:https://blog.csdn.net/handsome_for_kill/article/details/53130707#t3 ROS导航包的应用 利用ROS Navigation ...

  2. Luogu 4781 【模板】拉格朗日插值

    模板题. 拉格朗日插值的精髓在于这个公式 $$f(x) = \sum_{i = 1}^{n}y_i\prod _{j \neq i}\frac{x - x_i}{x_j - x_i}$$ 其中$(x_ ...

  3. 第二章启程前的认知准备,2.1Opencv官方例程引导与赏析

    1.在opencv安装目录下,可以找到opencv官方提供的示例代码,具体位于...\opencv\sources\samples目录下,如下所示 名为c的文件夹存放着opencv1.0等旧版本的示例 ...

  4. Python基础入门-元祖

    其实,元组合列表的特性和使用几乎差不太多,今天我们重点来看下元组的一些操作和使用. 1.元祖的定义和特点 定义:元组是以小括号包围,元素以逗号分隔,不可变的序列之一. 特点: 1)元祖内的元素不可以增 ...

  5. Customizing Site-Wide Behavior for ASP.NET Web Pages (Razor) Sites

    Customizing Site-Wide Behavior for ASP.NET Web Pages (Razor) Sites By Tom FitzMacken|February 17, 20 ...

  6. 第16章-使用Spring MVC创建REST API

    1 了解REST 1.1 REST的基础知识 REST与RPC几乎没有任何关系.RPC是面向服务的,并关注于行为和动作:而REST是面向资源的,强调描述应用程序的事物和名词. 为了理解REST是什么, ...

  7. BZOJ 2301 Problem b(莫比乌斯反演+分块优化)

    Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数 ...

  8. android eclipse 报error loading /system/media/audio/ xxx 错的解决办法。

    只针对 报错..error   loading /system/media/audio/ xxx.ogg 一步操作 解决烦恼..把 模拟器声音 关了..所有的错 都没了. 包括 关闭按键声音,触摸声音 ...

  9. 21天学通C++学习笔记(二):C++程序的组成部分

    1. 预处理器编译指令 预处理器是一个在编译前运行的工具. 预处理器编译指令是向预处理器发出的命令,总是以磅字符#大头. #include让预处理器获取指定文件并将它们放在编译指令所处的位置.#inc ...

  10. 关于PHP中的Trait

    今天看PHP框架,看到Trait部分.没见过,好奇查了一下. PHP手册说的是解决多继承的问题.但是一般面向对象的语言中,解决多继承都是通过接口,PHP也有接口.貌似看上去Trait和Interfac ...