BZOJ.2738.矩阵乘法(整体二分 二维树状数组)
整体二分。把求序列第K小的树状数组改成二维树状数组就行了。
初始答案区间有点大,离散化一下。
因为这题是一开始给点,之后询问,so可以先处理该区间值在l~mid的修改,再处理询问。即二分标准可以直接用点的标号。
结构体的赋值可以改为赋值操作的编号。(这样内存没那么连续?想多了你)
改了半下午,优化了500ms。。
//6980kb 10584ms 好慢啊QAQ
//4208ms 7.59MB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define lb(x) ((x)&-(x))
//#define gc() getchar()
#define MAXIN 500000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=505,M=60005;
int n,m,Ans[M],q[M],q1[M],q2[M];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Point
{
int x,y,val;
Point() {}
Point(int x,int y,int val):x(x),y(y),val(val) {}
bool operator <(const Point &a)const{
return val<a.val;
}
}pt[N*N];
inline int read();
struct Operation//Query
{
int K,x1,y1,x2,y2;
inline void Input(){
x1=read(),y1=read(),x2=read(),y2=read(),K=read();
}
}op[M];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
namespace T
{
int n,t[N][N];
inline void Modify(int x,int y,int v)
{
for(int i=x; i<=n; i+=lb(i))
for(int j=y; j<=n; j+=lb(j)) t[i][j]+=v;
}
inline void Clear(int x,int y)
{
for(int i=x; i<=n; i+=lb(i))
for(int j=y; j<=n; j+=lb(j))
if(t[i][j]) t[i][j]=0; else break;
}
inline int Query(int x,int y)
{
int res=0;
for(int i=x; i; i^=lb(i))
for(int j=y; j; j^=lb(j)) res+=t[i][j];
return res;
}
inline int Query_Area(Operation q){//prefix sum
return Query(q.x2,q.y2)-Query(q.x1-1,q.y2)-Query(q.x2,q.y1-1)+Query(q.x1-1,q.y1-1);
}
}
void Solve(int l,int r,int h,int t)
{
if(h>t) return;
if(l==r){
for(int i=h; i<=t; ++i) Ans[q[i]]/*[op[q[i]].pos]*/=pt[l].val;
return;
}
int mid=l+r>>1, t1=0, t2=0;
for(int i=l; i<=mid; ++i) T::Modify(pt[i].x,pt[i].y,1);
for(int now,tmp,i=h; i<=t; ++i)
{
now=q[i], tmp=T::Query_Area(op[now]);
if(tmp>=op[now].K) q1[t1++]=now;
else op[now].K-=tmp, q2[t2++]=now;
}
for(int i=l; i<=mid; ++i) T::Clear(pt[i].x,pt[i].y);
for(int i=0; i<t1; ++i) q[h+i]=q1[i];
for(int i=0; i<t2; ++i) q[h+t1+i]=q2[i];
Solve(l,mid,h,h+t1-1), Solve(mid+1,r,h+t1,t);
}
int main()
{
T::n=n=read(), m=read();
int tot=0;
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j) pt[++tot]=Point(i,j,read());
std::sort(pt+1,pt+1+tot);
for(int i=1; i<=m; ++i) q[i]=i, op[i].Input();
Solve(1,tot,1,m);
for(int i=1; i<=m; ++i) printf("%d\n",Ans[i]);
return 0;
}
优化前:
//4680ms 17.75MB
#include <cstdio>
#include <cctype>
#include <algorithm>
#define lb(x) ((x)&-(x))
//#define gc() getchar()
#define MAXIN 60000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=505,M=60005+N*N;
int n,m,Q,cnt,A[N*N],Ans[60005];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Operation
{
int K,x1,y1,x2,y2,pos;//K=0: Modify (x1,y1):=pos
Operation() {}
Operation(int K,int x1,int y1,int x2,int y2,int pos):K(K),x1(x1),y1(y1),x2(x2),y2(y2),pos(pos) {}
}q[M],q1[M],q2[M];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
namespace T
{
int n,t[N][N];
inline void Modify(int x,int y,int v)
{
for(int i=x; i<=n; i+=lb(i))
for(int j=y; j<=n; j+=lb(j)) t[i][j]+=v;
}
inline void Clear(int x,int y)
{
for(int i=x; i<=n; i+=lb(i))
for(int j=y; j<=n; j+=lb(j))
if(t[i][j]) t[i][j]=0; else break;
}
inline int Query(int x,int y)
{
int res=0;
for(int i=x; i; i^=lb(i))
for(int j=y; j; j^=lb(j)) res+=t[i][j];
return res;
}
inline int Query_Area(Operation q){//prefix sum
return Query(q.x2,q.y2)-Query(q.x1-1,q.y2)-Query(q.x2,q.y1-1)+Query(q.x1-1,q.y1-1);
}
}
void Solve(int l,int r,int h,int t)
{
if(h>t) return;
if(l==r){
for(int i=h; i<=t; ++i) if(q[i].K) Ans[q[i].pos]=A[l];
return;
}
bool goon=0;
for(int i=h; i<=t; ++i) if(q[i].K) {goon=1; break;}
if(!goon) return;
int mid=l+r>>1, midV=A[mid], t1=0, t2=0;
for(int i=h; i<=t; ++i)
if(q[i].K)
{
int tmp=T::Query_Area(q[i]);//这样好像少做几次加法!但是多copy两个int。。(你够了→_→)
if(tmp>=q[i].K) q1[t1++]=q[i];
else q[i].K-=tmp, q2[t2++]=q[i];
}
else
{
if(q[i].pos<=midV) T::Modify(q[i].x1,q[i].y1,1), q1[t1++]=q[i];
else q2[t2++]=q[i];
}
for(int i=0; i<t1; ++i) if(!q1[i].K) T::Clear(q1[i].x1,q1[i].y1);
for(int i=0; i<t1; ++i) q[h+i]=q1[i];
for(int i=0; i<t2; ++i) q[h+t1+i]=q2[i];
Solve(l,mid,h,h+t1-1), Solve(mid+1,r,h+t1,t);
}
int main()
{
T::n=n=read(), m=read(), Q=0;
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j) q[++Q]=Operation(0,i,j,0,0,A[Q]=read());
std::sort(A+1,A+1+Q), cnt=1;
for(int i=2; i<=Q; ++i) if(A[i]!=A[i-1]) A[++cnt]=A[i];
for(int x1,y1,x2,y2,i=1; i<=m; ++i)
x1=read(),y1=read(),x2=read(),y2=read(),q[++Q]=Operation(read(),x1,y1,x2,y2,i);
Solve(1,cnt,1,Q);
for(int i=1; i<=m; ++i) printf("%d\n",Ans[i]);
return 0;
}
BZOJ.2738.矩阵乘法(整体二分 二维树状数组)的更多相关文章
- 【bzoj2738】矩阵乘法 整体二分+二维树状数组
题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入 第一行两个数N,Q,表示矩阵大小和询问组数:接下来N行N列一共N*N个数,表示这个矩阵:再接下来Q行每行5个数 ...
- BZOJ2738矩阵乘法——整体二分+二维树状数组
题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入 第一行两个数N,Q,表示矩阵大小和询问组数:接下来N行N列一共N*N个数,表示这个矩阵:再接下来Q行每行5 ...
- [BZOJ2738]矩阵乘法 整体二分+二维树状数组
2738: 矩阵乘法 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1643 Solved: 715[Submit][Status][Discuss ...
- [BZOJ2738]矩阵乘法(整体二分+二维树状数组)
整体二分+二维树状数组. 好题啊!写了一个来小时. 一看这道题,主席树不会搞,只能用离线的做法了. 整体二分真是个好东西,啥都可以搞,尤其是区间第 \(k\) 大这种东西. 我们二分答案,然后用二维树 ...
- BZOJ 2738 矩阵乘法(整体二分+二维树状数组)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2738 [题目大意] 给出一个方格图,询问要求求出矩阵内第k小的元素 [题解] 我们对答 ...
- BZOJ 2738 子矩阵第k大 | 二维树状数组 整体二分 分治
BZOJ 2738 "矩阵乘法"(子矩阵第k大) 题意 给出一个矩阵,多次询问子矩阵中第k大的数是多少. 题解 我做这道题之前先照着这道题出了一道题,是这道题的一维版本,在这里:h ...
- 【清澄A1333】【整体二分+二维树状数组】矩阵乘法(梁盾)
试题来源 2012中国国家集训队命题答辩 问题描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入格式 第一行两个数N,Q,表示矩阵大小和询问组数: 接下来N行N列一共 ...
- BZOJ 2738: 矩阵乘法 [整体二分]
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 愚蠢的名字...... 整体二分,影响因子就是矩阵里的数 把$\le mid$的矩阵元素加到二维树状数组里然后询问分成两组就行 ...
- BZOJ 1452 Count 【模板】二维树状数组
对每种颜色开一个二维树状数组 #include<cstdio> #include<algorithm> using namespace std; ; ][maxn][maxn] ...
随机推荐
- vue组件之间传值方式解析
vue组件之间传值方式解析一.父组件传到子组件 1.父组件parent代码如下: <template> <div class="parent"> <h ...
- C++ Primer 5th 第17章 标准库特殊设施
C++新标准库提供了很多新功能,它们更加强大和易用. tuple类型 tuple是一种类似pair的模板,pair可以用来保存一对逻辑上有关联的元素对.但与pair不同的是,pair只能存储两个成员, ...
- ORB_SLAM2 源码阅读 ORB_SLAM2::Initializer::ComputeF21 (OpenCV 细节)
ORB_SLAM2 计算 F21 的代码是这样的. cv::Mat Initializer::ComputeF21(const vector<cv::Point2f> &vP1,c ...
- 个人对java中对象锁与类锁的一些理解与实例
一 什么是对象锁 对象锁也叫方法锁,是针对一个对象实例的,它只在该对象的某个内存位置声明一个标识该对象是否拥有锁,所有它只会锁住当前的对象,而并不会对其他对象实例的锁产生任何影响,不同对象访问同一个 ...
- 41 - 数据库-pymysql41 - 数据库-pymysql-DBUtils
目录 1 Python操作数据库 2 安装模块 3 基本使用 3.1 创建一个连接 3.2 连接数据库 3.3 游标 3.3.1 利用游标操作数据库 3.3.2 事务管理 3.3.3 执行SQL语句 ...
- redis从入门到放弃 -> 部署方案
单点部署方案 环境准备: [root@localhost ~]# cat /etc/redhat-release CentOS Linux release 7.2.1511 (Core) [root@ ...
- 09 Command Documentation 命令文档
Command Documentation 命令文档 There is a suite of programs to build and process Go source code. Inste ...
- 目标板通过nfs挂载根文件系统
目标板挂载根文件系统的方法有两种(这里所说的服务端就是ubuntu,Ubuntu已经成功安装了nfs服务,并且保证服务端与目标板ping 通) 第一种:等待开发板启动之后去挂载,此时文件系统从Flas ...
- 经典面试题:js继承方式上
js不是传统的面向对象语言,那么他是怎么实现继承的呢?由于js是基于原型链实现的面向对象,所以js主要通过原型链查找来实现继承,主要有两大类实现方式,分为基于构造函数的继承,以及非构造函数的继承. 由 ...
- java基础78 Servlet的生命周期
1.Servlet的生命周期 简单的解析就是: 创建servlet实例(调用构造器)---->调用init()方法---->调用service()方法----->调用destroy( ...