1. 程式人生 > >[BZOJ2738]矩陣乘法-[整體二分]

[BZOJ2738]矩陣乘法-[整體二分]

mil rec cti hit hid margin 矩陣乘法 n-2 imp

Description

給你一個N×N的矩陣,不用算矩陣乘法,但是每次詢問一個子矩形的第K小數。N500,Q60000

Solution

這個的話,二分答案,問題改為如何求矩陣的點數。考慮用二維的樹狀數組來計算。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct P{int num,x,y;}a[250010];int cnt_a=0;
bool cmp(P x,P y){return
x.num<y.num;} int rk[100100],all=0; int n,m; struct node{int x,y,xx,yy,k,id; }q[60010],st[2][60010];int ans[60010]; int tree[510][510]; void add(int x,int y,int data){for(;x<=n;x+=x&-x)for(int j=y;j<=n;j+=j&-j) tree[x][j]+=data;} int query(int x,int y){int re=0;for(;x;x-=x&-x)for(int j=y;j;j-=j&-j) re+=tree[x][j];return
re;} int now; void solve(int ql,int qr,int ansl,int ansr) { if (ql>qr) return; if (ansl==ansr) { for (int i=ql;i<=qr;i++) ans[q[i].id]=ansl; return; } int ansmid=ansl+ansr>>1,cnt,js0=0,js1=0; for (;now<ansmid;) now++,add(a[now].x,a[now].y,1);
for(;now>ansmid;now--) add(a[now].x,a[now].y,-1); for (int i=ql;i<=qr;i++) { cnt=query(q[i].xx,q[i].yy)+query(q[i].x-1,q[i].y-1)-query(q[i].x-1,q[i].yy)-query(q[i].xx,q[i].y-1); if (cnt>=q[i].k) st[0][++js0]=q[i]; else st[1][++js1]=q[i]; } for (int i=1;i<=js0;i++) q[i+ql-1]=st[0][i]; for (int i=1;i<=js1;i++) q[i+ql+js0-1]=st[1][i]; solve(ql,ql+js0-1,ansl,ansmid); solve(ql+js0,qr,ansmid+1,ansr); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { scanf("%d",&a[++cnt_a].num);a[cnt_a].x=i;a[cnt_a].y=j; } sort(a+1,a+cnt_a+1,cmp); for (int i=1;i<=m;i++) { scanf("%d%d%d%d%d",&q[i].x,&q[i].y,&q[i].xx,&q[i].yy,&q[i].k);q[i].id=i; } solve(1,m,0,n*n); for (int i=1;i<=m;i++) printf("%d\n",a[ans[i]].num); }

[BZOJ2738]矩陣乘法-[整體二分]