可以用二维树状数组套值域线段树来做,复杂度:O( (n*n+q) * logn logn log10^9 )
但作为作为整体二分的例题,还是用整体二分来写了一下。对整体二分有一点感觉了。
整体二分,顾名思义,二分答案,只不过不是对单独一个询问,而是对所有询问,具体过程可以想象成对询问的不断分类(根据其答案区间不断往下分)。比如最开始所有询问的答案区间是[amin,amax],我们现在分出两个区间[amin,amid],和[amid+1,amax],然后将当前区间[amin,amax]的所有询问根据某些信息,分配到两个区间,使得其答案的可能的区间范围就是它所属的区间,当区间长度为1时,该区间包含的询问的答案就是该区间的那个数。
形象一点,可以把二分比作赶鸭子(询问)回窝(答案),单独对一个询问二分是只赶一只鸭子,向左区间或右区间赶,直到回窝,而整体二分就是赶一群鸭子,前者只需单刀直入,找到答案,而后者还需要回朔。
整体二分的优势是可以在分配询问时共享一些东西,从而避免掉每次单独算的低效,从而优化复杂度。
1 #include <cstdio> 2 #include <vector> 3 #include <algorithm> 4 #define oo 0x3f3f3f3f 5 #define N 510 6 #define M 60010 7 using namespace std; 8 9 struct Pair { 10 int v; 11 int x, y; 12 Pair(){} 13 Pair( int v, int x, int y ):v(v),x(x),y(y){} 14 bool operator<( const Pair &o ) const { 15 return v<o.v; 16 } 17 }; 18 bool operator<( const Pair &a, int b ) { 19 return a.v<b; 20 } 21 bool operator<( int a, const Pair &b ) { 22 return a<b.v; 23 } 24 struct Query { 25 int id; 26 int xmin, xmax; 27 int ymin, ymax; 28 int k; 29 Query( int id, int x0, int x1, int y0, int y1, int k ): 30 id(id),xmin(x0),xmax(x1),ymin(y0),ymax(y1),k(k){} 31 }; 32 33 int n, m; 34 int ww[N][N], vmin, vmax; 35 int bit[N][N]; 36 int ans[M]; 37 Pair prs[N*N]; int ptot; 38 vector<Query> vq; 39 int q[N*N]; 40 41 void modify( int x, int y, int v ) { 42 for( register int i=x; i<=n; i+=i&-i ) 43 for( register int j=y; j<=n; j+=j&-j ) 44 bit[i][j] += v; 45 } 46 int query( int x, int y ) { 47 int rt = 0; 48 for( register int i=x; i; i-=i&-i ) 49 for( register int j=y; j; j-=j&-j ) 50 rt += bit[i][j]; 51 return rt; 52 } 53 int query( int xmin, int xmax, int ymin, int ymax ) { 54 return query(xmax,ymax)-query(xmin-1,ymax)-query(xmax,ymin-1)+query(xmin-1,ymin-1); 55 } 56 void binary( int lf, int rg, vector<Query> vq ) { 57 if( vq.empty() ) return; 58 if( lf==rg ) { 59 for( int t=0; t<vq.size(); t++ ) 60 ans[vq[t].id] = lf; 61 return; 62 } 63 int mid=lf+((rg-lf)>>1); 64 int lpos = lower_bound( prs+1, prs+1+ptot, lf ) - prs; 65 int rpos = upper_bound( prs+1, prs+1+ptot, mid ) - prs - 1; 66 for( int i=lpos; i<=rpos; i++ ) 67 modify( prs[i].x, prs[i].y, +1 ); 68 vector<Query> ql, qr; 69 for( int t=0; t<vq.size(); t++ ) { 70 int c = query( vq[t].xmin, vq[t].xmax, vq[t].ymin, vq[t].ymax ); 71 if( vq[t].k<=c ) 72 ql.push_back( vq[t] ); 73 else { 74 qr.push_back( vq[t] ); 75 qr.back().k -= c; 76 } 77 } 78 for( int i=lpos; i<=rpos; i++ ) 79 modify( prs[i].x, prs[i].y, -1 ); 80 binary( lf, mid, ql ); 81 binary( mid+1, rg, qr ); 82 } 83 int main() { 84 scanf( "%d%d", &n, &m ); 85 vmin=oo, vmax=-oo; 86 for( int i=1; i<=n; i++ ) 87 for( int j=1; j<=n; j++ ) { 88 scanf( "%d", &ww[i][j] ); 89 vmin = min( vmin, ww[i][j] ); 90 vmax = max( vmax, ww[i][j] ); 91 prs[++ptot] = Pair( ww[i][j], i, j ); 92 } 93 sort( prs+1, prs+1+ptot ); 94 for( int i=1,x0,x1,y0,y1,k; i<=m; i++ ) { 95 scanf( "%d%d%d%d%d", &x0, &y0, &x1, &y1, &k ); 96 vq.push_back( Query( i, x0, x1, y0, y1, k ) ); 97 } 98 binary( vmin, vmax, vq ); 99 for( int i=1; i<=m; i++ ) 100 printf( "%d ", ans[i] ); 101 }