P4148 简单题

题目链接

P4148 简单题

题目描述

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

  • 1 x y A \(1\le x,y\le N\)\(A\) 是正整数。将格子x,y里的数字加上 \(A\)
  • 2 x1 y1 x2 y2 \(1 \le x_1 \le x_2 \le N\)\(1 \le y_1\le y_2 \le N\)。输出 \(x_1, y_1, x_2, y_2\) 这个矩形内的数字和
  • 3 无 终止程序

输入格式

输入文件第一行一个正整数 \(N\)

接下来每行一个操作。每条命令除第一个数字之外,均要异或上一次输出的答案 last_ans,初始时 last_ans \(=0\)

输出格式

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

样例 #1

样例输入 #1

4
1 2 3 3
2 1 1 3 3
1 1 1 1
2 1 1 0 7
3

样例输出 #1

3
5

提示

\(1\leq N\leq 5\times 10^5\),操作数不超过 \(2\times 10^5\) 个,内存限制 \(20\texttt{MB}\),保证答案在 int 范围内并且解码之后数据仍合法。

解题思路

kdtree

kdtree 插入节点时按照 kdtree 性质插入:每次插入时判断根节点的划分维度,然后根据该维度跟根节点进行比较判断向左/右子树插入,另外由于每次插入到叶子节点后还需要划分一个维度,叶子节点可以随机划分,但是最终形成的树可能不是很平衡,这时可采用替罪羊树暴力重构的思想,即当某一棵子树没有达到平衡要求时暴力重构该子树
kdtree 矩阵查询时共三种情况:查询的矩阵完全包含整棵子树以及查询的矩阵完全在整棵子树外面,这时可以直接 return,其他有交集的情况递归查询即可

单次矩阵查询最优时间复杂度:\(O(logn)\)
矩阵查询均摊时间复杂度:\(O(\sqrt{n})\)

  • 时间复杂度:\(O(n\sqrt{n})\)

代码

// Problem: P4148 简单题
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4148
// Memory Limit: 20 MB
// Time Limit: 8000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=2e5+5;
const double alpha=0.75;
int n,cnt,root;
int a[N],idx;
struct Point
{
	int x,y,v;
}point[N];
struct Tr
{
	int s[2];
	int U,D,L,R;
	int sz,sum,dim;
}tr[N];
void pushup(int x)
{
	tr[x].sum=tr[tr[x].s[0]].sum+tr[tr[x].s[1]].sum+point[x].v;
	tr[x].sz=tr[tr[x].s[0]].sz+tr[tr[x].s[1]].sz+1;
	tr[x].L=tr[x].R=point[x].x,tr[x].U=tr[x].D=point[x].y;
	if(tr[x].s[0])
	{
		tr[x].L=min(tr[x].L,tr[tr[x].s[0]].L);
		tr[x].D=min(tr[x].D,tr[tr[x].s[0]].D);
		tr[x].R=max(tr[x].R,tr[tr[x].s[0]].R);
		tr[x].U=max(tr[x].U,tr[tr[x].s[0]].U);
	}
	if(tr[x].s[1])
	{
		tr[x].L=min(tr[x].L,tr[tr[x].s[1]].L);
		tr[x].D=min(tr[x].D,tr[tr[x].s[1]].D);
		tr[x].R=max(tr[x].R,tr[tr[x].s[1]].R);
		tr[x].U=max(tr[x].U,tr[tr[x].s[1]].U);
	}
}
void inorder(int x)
{
	if(!x)return ;
	inorder(tr[x].s[0]);
	a[++idx]=x;
	inorder(tr[x].s[1]);
}
bool cmp1(const int &x,const int &y)
{
	return point[x].x<point[y].x;
}
bool cmp2(const int &x,const int &y)
{
	return point[x].y<point[y].y;
}
int build(int l,int r)
{
	if(l>r)return 0;
	int mid=l+r>>1;
	double avg[2]={0},va[2]={0};
	for(int i=l;i<=r;i++)avg[0]+=point[a[i]].x,avg[1]+=point[a[i]].y;
	avg[0]/=(r-l+1),avg[1]/=(r-l+1);
	for(int i=l;i<=r;i++)
	{
		va[0]+=(point[a[i]].x-avg[0])*(point[a[i]].x-avg[0]);
		va[1]+=(point[a[i]].y-avg[1])*(point[a[i]].y-avg[1]);
	}
	if(va[0]>va[1])nth_element(a+l,a+mid,a+r+1,cmp1),tr[a[mid]].dim=1;
	else
		nth_element(a+l,a+mid,a+r+1,cmp2),tr[a[mid]].dim=0;
	tr[a[mid]].s[0]=build(l,mid-1),tr[a[mid]].s[1]=build(mid+1,r);
	pushup(a[mid]);
	return a[mid];
}
void rebuild(int &x)
{
	idx=0;
	inorder(x);
	x=build(1,idx);
}
bool bad(int x)
{
	return alpha*tr[x].sz<=max(tr[tr[x].s[0]].sz,tr[tr[x].s[1]].sz);
}
void insert(int &p,int x)
{
	if(!p)
	{
		p=x;
		tr[p].dim=rand()%2;
		pushup(p);
		return ;
	}
	if(tr[p].dim)
	{
		if(point[x].x<=point[p].x)insert(tr[p].s[0],x);
		else
			insert(tr[p].s[1],x);
	}
	else
	{
		if(point[x].y<=point[p].y)insert(tr[p].s[0],x);
		else
			insert(tr[p].s[1],x);
	}
	pushup(p);
	if(bad(p))rebuild(p);
}
int ask(int p,int l,int d,int r,int u)
{
	if(!p||l>tr[p].R||r<tr[p].L||u<tr[p].D||d>tr[p].U)return 0;
	if(l<=tr[p].L&&tr[p].R<=r&&d<=tr[p].D&&tr[p].U<=u)return tr[p].sum;
	int res=0;
	if(l<=point[p].x&&point[p].x<=r&&d<=point[p].y&&point[p].y<=u)
		res+=point[p].v;
	return res+ask(tr[p].s[0],l,d,r,u)+ask(tr[p].s[1],l,d,r,u);
}
int main()
{
    int op,x[2],y[2],lstans=0;
    scanf("%d",&n);
    while(scanf("%d",&op),op!=3)
    {
    	if(op==1)
    	{
    		cnt++;
    		scanf("%d%d%d",&point[cnt].x,&point[cnt].y,&point[cnt].v);
    		point[cnt].x^=lstans,point[cnt].y^=lstans,point[cnt].v^=lstans;
    		insert(root,cnt);
    	}
    	else
    	{
    		scanf("%d%d%d%d",&x[0],&y[0],&x[1],&y[1]);
    		x[0]^=lstans,y[0]^=lstans,x[1]^=lstans,y[1]^=lstans;
    		printf("%d\n",lstans=ask(root,x[0],y[0],x[1],y[1]));
    	}
    }
    return 0;
}
posted @ 2022-10-26 21:04  zyy2001  阅读(24)  评论(0编辑  收藏  举报