[BZOJ 2738]矩阵乘法

本文探讨了在处理大量插入操作时,通过使用整数下标排序而非排序数组,以减少复制时间,优化批量插入操作效率。介绍了使用二进制指数查找树(BIT)进行快速更新和查询操作的方法。

卡时卡的我心塞啊

因为插入操作太多而且没有顺序我们需要在sort后的插入操作上滚来滚去= =

其实并不需要排序opt数组,而用int下标排序可避免复制的时间过长。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#define maxn 510
using namespace std;

void read(int &num){
	num = 0;char ch = getchar();
	for(;ch < '!'; ch = getchar());
	for(;ch > '!'; ch = getchar())
		num = num * 10 + ch - 48;
}
int N, Q;
//BIT{
	int t[maxn][maxn];
	int lowbit[maxn];
	#define lowbit_cal(x) (x & ((~x) + 1))

	void update(int x, int y, const int& val){
		if(!x || !y)return;
		int tmp = y;
		while(x <= N){
			y = tmp;
			while(y <= N){
				t[x][y] += val;
				y += lowbit_cal(y);
			}
			x += lowbit_cal(x);
		}
	}
	
	int ask(int x, int y){
        if(!x || !y)return 0;
		int tmp = y, ans = 0;
		while(x){
			y = tmp;
			while(y){
				ans += t[x][y];
				y -= lowbit_cal(y);
			}
			x -= lowbit_cal(x);
		}
		return ans;
	}
	
	int ask(const int& x1, const int& y1, const int& x2, const int& y2){
		int ans = ask(x1 - 1, y1 - 1) + ask(x2, y2);
		ans -= ask(x2, y1 - 1) + ask(x1 - 1, y2);
		return ans;
	}




int n;
#define maxq 310010
struct opt{
	int x1, y1, tp;
	int x2, y2, k;
	bool operator<(const opt& k)const{
		return tp < k.tp;
	}
}q[maxq], q1[maxq], q2[maxq];

const int inf = 0x7fffffff;

int TMP, ans[maxq];

int T = 0;

void solve(int head, int tail, int l, int r){
    //cout << head << ' ' << tail << ' ' << l << ' ' << r << endl;
	if(head > tail)return;
	if(l == r){
		for(int i = head; i <= tail; i ++)
			ans[q[i].tp] = l;
		return;
	}
	int mid = l + r >> 1;
	while(q[T + 1].tp <= mid && T < TMP)
	    T ++, update(q[T].x1, q[T].y1, 1);
	while(q[T].tp > mid && T)
	    update(q[T].x1, q[T].y1, -1), T --;

	int l1 = 0, l2 = 0;
	for(int i = head; i <= tail; i ++){
		if(ask(q[i].x1, q[i].y1, q[i].x2, q[i].y2) >= q[i].k)
			q1[++ l1] = q[i];
		else{
			//q[i].k -= tmp[i];
			q2[++ l2] = q[i];
		}
	}
	
	int cnt = head;
	for(int i = 1; i <= l1; i ++)q[cnt ++] = q1[i];
	for(int i = 1; i <= l2; i ++)q[cnt ++] = q2[i];

//	memcpy(q + head, q1 + 1, sizeof (q[0]) * l1);
//	memcpy(q + head + l1, q2 + 1, sizeof (q[0]) * l2);
	solve(head, head + l1 - 1, l, mid);
	solve(head + l1, tail, mid + 1, r);
}



int main(){
    freopen("nt2012_mat.in","r",stdin);
	freopen("nt2012_mat.out","w",stdout);
	
	read(N);
	read(Q);
	TMP = N * N;

	int x;
	int mn = inf, mx = -inf;

	for(int i = 1; i <= N; i ++){
		for(int j = 1; j <= N; j ++){
			read(x);
	        if(x < mn)mn = x;
			if(x > mx)mx = x;
			++ n;
			q[n].x1 = i;
			q[n].y1 = j;
			q[n].tp = x;
		}
	}
	sort(q + 1, q + 1 + n);

	int id = 0;
	for(int i = 1; i <= Q; i ++){
		++ n;
		read(q[n].x1), read(q[n].y1);
		read(q[n].x2), read(q[n].y2);
		read(q[n].k);
		q[n].tp = ++ id;
	}
	solve(TMP + 1, n, mn, mx);
   
	for(int i = 1; i <= Q; i ++)
		printf("%d\n", ans[i]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值