矩阵乘法 bzoj-2738

题目大意:给定一个$n*n$的矩阵。每次给定一个矩阵求矩阵$k$小值。

注释:$1\le n\le 500$,$1\le q\le 6\cdot 10^4$。


想法

新操作整体二分。

整体二分是一个必须离线的算法而且所求的答案必须满足单调性。

所谓单调性就是比如这个题:k越大那么对应的答案越大。

进而我们将所有操作在权值上整体二分。

每次假设当前权值区间为$[l,r]$。

先用二维树状数组求出每个矩形[l,mid]中的点个数然后暴力转移即可。

暴力转移就是看一下$k_i$和个数哪个比较大,考虑把当前操作扔进左区间还是右区间。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 510
#define M 60010
using namespace std;
int tree[N<<1][N<<1],ans[M],n,m;
struct pnt {int x,y,val;}a[N*N]; inline bool cmp(const pnt &a,const pnt &b) {return a.val<b.val;}
struct Node {int x1,x2,y1,y2,k,id;}q[M],t[M];
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
inline int lowbit(int x) {return x&(-x);}
void update(int x,int y,int val)
{
for(int i=x;i<=n+1;i+=lowbit(i)) for(int j=y;j<=n+1;j+=lowbit(j)) tree[i][j]+=val;
}
int query(int x,int y)
{
int ans=0; for(int i=x;i>=1;i-=lowbit(i)) for(int j=y;j>=1;j-=lowbit(j)) ans+=tree[i][j];
return ans;
}
void solve(int x,int y,int l,int r)
{
int tl=x,tr=y;
if(x>y) return;
if(l==r)
{
for(int i=x;i<=y;i++) ans[q[i].id]=a[l].val;
return;
}
int mid=(l+r)>>1;
for(int i=l;i<=mid;i++) update(a[i].x,a[i].y,1);
for(int i=x;i<=y;i++)
{
int dlt=query(q[i].x1-1,q[i].y1-1)+query(q[i].x2,q[i].y2)-query(q[i].x1-1,q[i].y2)-query(q[i].x2,q[i].y1-1);
if(q[i].k<=dlt) t[tl++]=q[i];
else q[i].k-=dlt,t[tr--]=q[i];
}
for(int i=x;i<=y;i++) q[i]=t[i];
for(int i=l;i<=mid;i++) update(a[i].x,a[i].y,-1);
solve(x,tr,l,mid); solve(tl,y,mid+1,r);
}
int main()
{
n=rd(),m=rd(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
{
int id=(i-1)*n+j;
a[id].val=rd(); a[id].x=i,a[id].y=j;
}
sort(a+1,a+n*n+1,cmp);
for(int i=1;i<=m;i++) q[i].x1=rd(),q[i].y1=rd(),q[i].x2=rd(),q[i].y2=rd(),q[i].k=rd(),q[i].id=i;
solve(1,m,1,n*n);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}

小结:整体二分好好玩~

最新文章

  1. win2012,oracle11g,sqlplus切换实例的方法
  2. IQueryable join 的问题
  3. 十进制数转化成二进制后包含一的数量(c++)
  4. [Linux] ubuntu安装配置vsftpd并锁定目录
  5. 51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛
  6. JSOI2015 R3 退队滚粗了
  7. python运维开发之第十天
  8. C++线性序列容器&lt;vector&gt;简单总结
  9. epoll模型的et模式和lt模式
  10. Java重写方法与初始化的隐患(转)
  11. iOS-Runtime机制详解
  12. 用Django Rest Framework和AngularJS开始你的项目
  13. easyui message show中msg嵌入一个按钮如何绑定事件
  14. SSIS 实用表达式部分总结
  15. Guns(开源后台管理系统框架)实战(一)——开发环境搭建
  16. c#错误cs0006
  17. springboot 注解整理
  18. Java中的集合迭代器
  19. Opaque data type--不透明类型
  20. Kernel parameter requirements ( Linux DB2)

热门文章

  1. 使用nginx搭建简单文件服务器
  2. Hadoop YARN学习监控JVM和实时监控Ganglia、Ambari(5)
  3. 语音行业技术领先者Nuance上海诚招ASR/NLP研发工程师和软件工程师
  4. dd - 转换和拷贝文件
  5. windows/linux 更新python pip
  6. 开源敏捷测试管理&amp; 开源BUG跟踪管理软件itest(爱测试) V3.3.0隆重发布
  7. jquery中ajax原生代码的分析模仿
  8. BZOJ 3876 支线剧情 有源汇有上下界最小费用可行流
  9. l5-repository基本使用
  10. &lt;input type=&quot;button&quot; /&gt; 和&lt;input type=&quot;submit&quot; /&gt; 的区别