链接
http://www.lydsy.com/JudgeOnline/problem.php?id=2738
题解
我百度了题解发现是整体二分,点开黄学长的题解看了看,然后就自行脑补了一个整体二分。写的不仅丑而且常数巨大。不太想深入学,因为考到的概率确实不大。
其实表面上叫做整体二分,实现起来也确实像二分,但算法的实质是分治。
大致思想就是二分答案,然后看看哪些询问的答案比二分的答案大,哪些小,递归分治下去。
这道题就可以二分答案
mid
,每次把权值小于等于
mid
的数对应位置上
+1
(可以用二维BIT实现)。然后扫描当前的询问,对于一个询问看它对应的那个子矩形中已经插入了几个数,如果插入的数的个数比询问的
k
<script type="math/tex" id="MathJax-Element-161">k</script>大,就说明枚举的答案过大,就把当前询问加入左边,否则加入右边。
然后分治下去。
代码
//整体二分、二维BIT
#include <cstdio>
#include <algorithm>
#define maxn 510
#define maxq 70000
#define lowbit(x) (x&-x)
using namespace std;
int bit[maxn][maxn], x1[maxq], x2[maxq], y1[maxq], y2[maxq], ans[maxq], w[maxn][maxn],
N, Q, k[maxq], xu[maxn*maxn], p, x[maxn*maxn], y[maxn*maxn];
void add(int x, int y, int v)
{
int i, j;
for(i=x;i<=N;i+=lowbit(i))
for(j=y;j<=N;j+=lowbit(j))bit[i][j]+=v;
}
int sum(int x, int y)
{
int ans=0, i, j;
for(i=x;i;i-=lowbit(i))for(j=y;j;j-=lowbit(j))ans+=bit[i][j];
return ans;
}
int q(int n)
{return sum(x2[n],y2[n])-sum(x1[n],y2[n])-sum(x2[n],y1[n])+sum(x1[n],y1[n]);}
void bin(int *num, int l, int r)
{
int i, j, mid=l+r>>1, lq[num[0]+5], rq[num[0]+5];
if(l==r){for(i=1;i<=num[0];i++)ans[num[i]]=mid;return;}
while(w[x[xu[p+1]]][y[xu[p+1]]]<=mid)p++,add(x[xu[p]],y[xu[p]],1);
while(w[x[xu[p]]][y[xu[p]]]>mid and p)add(x[xu[p]],y[xu[p]],-1),p--;
lq[0]=rq[0]=0;
for(i=1;i<=num[0];i++)
{
if(q(num[i])>=k[num[i]])lq[++lq[0]]=num[i];
else rq[++rq[0]]=num[i];
}
if(lq[0])bin(lq,l,mid);
if(rq[0])bin(rq,mid+1,r);
}
int read(int x=0)
{
char c=getchar();
while(c<48 or c>57)c=getchar();
while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48, c=getchar();
return x;
}
bool cmp(int a, int b){return w[x[a]][y[a]]<w[x[b]][y[b]];}
void init()
{
int i, j, t;
N=read(), Q=read();
for(i=1;i<=N;i++)for(j=1;j<=N;j++)w[i][j]=read();
for(i=1;i<=Q;i++)
x1[i]=read()-1, y1[i]=read()-1, x2[i]=read(), y2[i]=read(), k[i]=read();
for(i=1;i<=N;i++)for(j=1;j<=N;j++)
{
t=(i-1)*N+j;
xu[t]=t;
x[t]=i, y[t]=j;
}
w[0][0]=0x7fffffff;
sort(xu+1,xu+N*N+1,cmp);
}
int main()
{
int i, num[maxq];
init();
for(i=1;i<=Q;i++)num[i]=i;num[0]=Q;
bin(num,1,1e9);
for(i=1;i<=Q;i++)printf("%d\n",ans[i]);
return 0;
}