P4148 简单题

题目链接

P4148 简单题

题目描述

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

  • 1 x y A 1x,yNA 是正整数。将格子x,y里的数字加上 A
  • 2 x1 y1 x2 y2 1x1x2N1y1y2N。输出 x1,y1,x2,y2 这个矩形内的数字和
  • 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

提示

1N5×105,操作数不超过 2×105 个,内存限制 20MB,保证答案在 int 范围内并且解码之后数据仍合法。

解题思路

kdtree

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

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

  • 时间复杂度:O(nn)

代码

// 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; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16830049.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2021-10-26 拓扑排序
点击右上角即可分享
微信分享提示