[bzoj4066/2683]简单题_KD-Tree

简单题 bzoj-4066

题目大意:n*n的棋盘,开始为均为0,支持:单点加权值,查询矩阵权值和,强制在线。

注释:$1\le n\le 5\cdot 10^5$,$1\le m \le 2\cdot 10^5$。



想法:KD-Tree裸题。

所谓KD-Tree,就是一个看起来贼牛逼实际上我觉着也贼牛逼的暴力... ...

算了,网上讲解一摞摞,不赘述。

这里我们只需要在KD-Tree上维护子树和即可。单点加的话往上更新呗,或者换成删除+插入也能过。

最后,附上丑陋的代码... ...

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 500010
using namespace std;
struct data
{
	int p[2],maxn[2],minn[2],c[2],w,sum;
}a[N];
int d,root;
inline bool cmp(const data &a,const data &b)
{
	return a.p[d]==b.p[d]?a.p[d^1]<b.p[d^1]:a.p[d]<b.p[d];
}
inline void pushup(int k,int s)
{
	a[k].maxn[0]=max(a[k].maxn[0],a[s].maxn[0]);
	a[k].minn[0]=min(a[k].minn[0],a[s].minn[0]);
	a[k].maxn[1]=max(a[k].maxn[1],a[s].maxn[1]);
	a[k].minn[1]=min(a[k].minn[1],a[s].minn[1]);
	a[k].sum+=a[s].sum;
}
int build(int l,int r,int now)
{
	int mid=(l+r)>>1;
	d=now,nth_element(a+l,a+mid,a+r+1,cmp);
	a[mid].maxn[0]=a[mid].minn[0]=a[mid].p[0];
	a[mid].maxn[1]=a[mid].minn[1]=a[mid].p[1];
	a[mid].sum=a[mid].w;
	a[mid].c[0]=a[mid].c[1]=0;
	if(l<mid)a[mid].c[0]=build(l,mid-1,now^1),pushup(mid,a[mid].c[0]);
	if(r>mid)a[mid].c[1]=build(mid+1,r,now^1),pushup(mid,a[mid].c[1]);
	return mid;
}
void ins(int x)
{
	int *t=&root;
	d=0;
	while(*t)pushup(*t,x),t=&a[*t].c[a[x].p[d]>a[*t].p[d]],d^=1;
	*t=x;
}
int query(int k,int x1,int y1,int x2,int y2)
{
	if(!k||a[k].maxn[0]<x1||a[k].maxn[1]<y1||a[k].minn[0]>x2||a[k].minn[1]>y2)return 0;
	if(a[k].maxn[0]<=x2&&a[k].maxn[1]<=y2&&a[k].minn[0]>=x1&&a[k].minn[1]>=y1)return a[k].sum;
	int ans=0;
	if(a[k].p[0]>=x1&&a[k].p[0]<=x2&&a[k].p[1]>=y1&&a[k].p[1]<=y2)ans+=a[k].w;
	ans+=query(a[k].c[0],x1,y1,x2,y2)+query(a[k].c[1],x1,y1,x2,y2);
	return ans;
}
int main()
{
	int opt,x1,y1,x2,y2,last=0,tot=0;
	scanf("%*d");
	while(scanf("%d",&opt)!=EOF&&opt!=3)
	{
		if(opt==1)
		{
			tot++,scanf("%d%d%d",&a[tot].p[0],&a[tot].p[1],&a[tot].w);
			a[tot].p[0]^=last,a[tot].p[1]^=last,a[tot].w^=last,a[tot].sum=a[tot].w;
			a[tot].maxn[0]=a[tot].minn[0]=a[tot].p[0];
			a[tot].maxn[1]=a[tot].minn[1]=a[tot].p[1];
			ins(tot);
			if(tot%10000==0)root=build(1,tot,0);
		}
		else scanf("%d%d%d%d",&x1,&y1,&x2,&y2),x1^=last,y1^=last,x2^=last,y2^=last,printf("%d\n",last=query(root,x1,y1,x2,y2));
	}
	return 0;
}

小结:KD-Tree更好玩... ...

原文地址:https://www.cnblogs.com/ShuraK/p/9383758.html

时间: 2024-10-08 18:37:25

[bzoj4066/2683]简单题_KD-Tree的相关文章

【BZOJ4066】简单题 KDtree

[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. 接下来每行一个操作.每条命令除第

bzoj 2683: 简单题

2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1779  Solved: 720[Submit][Status][Discuss] 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<

BZOJ 2683 简单题 ——CDQ分治

简单题 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define maxn 2000005 int sum[maxn]; void a

bzoj 2683 简单题 cdq分治

题面 题目传送门 解法 可以离线,那么就是非常简单的cdq分治了 只要把询问拆成4个,然后就变成了一个三维偏序问题 时间复杂度:\(O(q\ log^2\ n)\) 代码 #include <bits/stdc++.h> #define int long long #define N 1000010 using namespace std; template <typename node> void chkmax(node &x, node y) {x = max(x, y

【bzoj4066】 简单题

http://www.lydsy.com/JudgeOnline/problem.php?id=4066 (题目链接) 题意 维护一个矩阵,两个操作,给某一个元素加上A,求其中一个子矩阵的元素之和.强制在线. Solution KDtree,其它的就是跟平衡树的维护差不多. 然而我现在还是TLE啊T_T,但是正确性拍过没问题,求大佬帮忙看看哪里挂了T_T 细节 注意重新构树的时候,叶子节点的左右儿子要重新赋为0,因为最初它们的左右儿子并不是0. 代码 // bzoj4066 #include<a

BZOJ 2683 简单题 cdq分治+树状数组

题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后,二维的数据结构是显然不能过的,于是我们可能会考虑把一维排序之后另一位上数据结构什么的,然而cdq分治却能够很好的体现它的作用. 首先,对于每一个询问求和,显然是x在它左边的并且出现时间在它之前的所有的change对他可能会有影响. 我们按照x第一关键字,y第二关键字,操作第三关键字来排序所有的询问,然后在cdq的时候,每次递归处理左半区间,按照x动态的将y这一列的值加到树状数组里,来更新右半边的所有询问,注意这

【bzoj4066】简单题 KD-tree

题目描述 你有一个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 无 终止程序 输入 输入文件第一行一个正整数N. 接下来每行一个操作.每条命令除第一个数字之外,均要异或上一次输出的答案last_

【BZOJ-1176&amp;2683】Mokia&amp;简单题 CDQ分治

1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1854  Solved: 821[Submit][Status][Discuss] Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

bzoj2683简单题

2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MB Submit: 738  Solved: 307 [Submit][Status][Discuss] 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<