HYSBZ - 4066 简单题

题意:

给定一个 n × n 的棋盘,每个格子初始权值为 0,现有 m 次操作,①:1,x,y,v,在格子 ( x,y ) 加上权值 v;② :2,x1,y1,x2,y2,询问此子矩阵内的权值和。(n <= 5e5, m <= 2e5,内存限制20Mb,时限50s,强制在线)

链接:

https://vjudge.net/problem/HYSBZ-4066

解题思路:

这是一个经典问题,离线做法有如cdq分治、树状数组,在线做法有如树套树,半在线的主席树等(有空要整理一下),但是在这里通通用不了。这里用 K-D Tree 来解决,空间O(n),插入O(logn),查询O( n \sqrt{n} n )(k = 2维)。
然后,维护的东西比较多写成结构体会快一些,特别是这题 50s,第一次遇到这么长时限的,结果用非结构体写 T 到飞起,都是血泪啊。

参考代码:
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 2e5 + 5;
const int maxm = 5e2 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;

const int maxs = 1e3 + 5;
char buf[maxs], *p1 = buf, *p2 = buf;
inline char fr(){

	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, maxs, stdin)) == p1 ? -1 : *p1++;
}
#define gc fr()
inline void read(int &x){

	char ch; while(!isdigit(ch = gc)); x = ch ^ 48;
	while(isdigit(ch = gc)) x = x * 10 + (ch ^ 48);
}

int idx, n, k, rt, tot, cnt;
struct Point{
	int x[2], w;
	bool operator < (const Point &o) const{
		return x[idx] < o.x[idx];
	}
} pi[maxn];
struct Node{
	Point po;
	int ls, rs, mn[2], mx[2], siz, sum;
} tr[maxn];
int rub[maxn], top;
const double ak = 0.625;

inline int add(){

	if(top) return rub[top--];
	return ++tot;
}

void pushUp(int rt){

	int l = tr[rt].ls, r = tr[rt].rs;
	for(int i = 0; i < k; ++i){

		tr[rt].mn[i] = tr[rt].mx[i] = tr[rt].po.x[i];
		if(l) tr[rt].mn[i] = min(tr[rt].mn[i], tr[l].mn[i]);
		if(r) tr[rt].mn[i] = min(tr[rt].mn[i], tr[r].mn[i]);
		if(l) tr[rt].mx[i] = max(tr[rt].mx[i], tr[l].mx[i]);
		if(r) tr[rt].mx[i] = max(tr[rt].mx[i], tr[r].mx[i]);
	}
	tr[rt].siz = tr[l].siz + tr[r].siz + 1;
	tr[rt].sum = tr[l].sum + tr[r].sum + tr[rt].po.w;
}

void build(int l, int r, int &rt, int d){

	rt = add(); tr[rt].ls = tr[rt].rs = 0;
	int mid = gmid; idx = d;
	nth_element(pi + l, pi + mid, pi + 1 + r);
	tr[rt].po = pi[mid];
	if(l < mid) build(l, mid - 1, tr[rt].ls, d ^ 1);
	if(r > mid) build(mid + 1, r, tr[rt].rs, d ^ 1);
	pushUp(rt);
}

inline int check(int rt){

	if(max(tr[tr[rt].ls].siz, tr[tr[rt].rs].siz) > tr[rt].siz * ak) return 1;
	return 0;
}

void print(int rt){

	if(tr[rt].ls) print(tr[rt].ls);
	if(tr[rt].rs) print(tr[rt].rs);
	pi[++cnt] = tr[rt].po, rub[++top] = rt;
}

void rebuild(int &rt, int d){

	cnt = 0;
	print(rt);
	build(1, cnt, rt, d);
}

void update(int &rt, int d, Point &a){

	if(!rt){

		rt = add(); tr[rt].ls = tr[rt].rs = 0;
		tr[rt].po = a; pushUp(rt);
		return;
	}
	if(a.x[d] <= tr[rt].po.x[d]) update(tr[rt].ls, d ^ 1, a);
	else update(tr[rt].rs, d ^ 1, a);
	pushUp(rt);
	if(check(rt)) rebuild(rt, d);
}

int query(int rt, int x1, int y1, int x2, int y2){

	if(!rt || x2 < tr[rt].mn[0] || x1 > tr[rt].mx[0] || y2 < tr[rt].mn[1] || y1 > tr[rt].mx[1]) return 0;
	if(x1 <= tr[rt].mn[0] && x2 >= tr[rt].mx[0] && y1 <= tr[rt].mn[1] && y2 >= tr[rt].mx[1]) return tr[rt].sum;
	int ret = 0;
	if(x1 <= tr[rt].po.x[0] && x2 >= tr[rt].po.x[0] && y1 <= tr[rt].po.x[1] && y2 >= tr[rt].po.x[1]) ret += tr[rt].po.w;
	return ret + query(tr[rt].ls, x1, y1, x2, y2) + query(tr[rt].rs, x1, y1, x2, y2);
}

int main(){

	read(n); k = 2;
	int opt, x1, y1, x2, y2, ret = 0;
	while(1){

		read(opt);
		if(opt == 1){

			Point a;
			read(a.x[0]), read(a.x[1]), read(a.w);
			a.x[0] ^= ret, a.x[1] ^= ret, a.w ^= ret;
			update(rt, 0, a);
		}
		else if(opt == 2){

			read(x1), read(y1), read(x2), read(y2);
			x1 ^= ret, y1 ^= ret, x2 ^= ret, y2 ^= ret;
			ret = query(rt, x1, y1, x2, y2);
			printf("%d\n", ret);
		}
		else break;
	}
	return 0;
}
好的,你可以参考以下示例代码实现Java销售额查询和营业额统计: ```java import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class SalesStatistics { private Map<String, Double> salesData = new HashMap<>(); public SalesStatistics() { // 初始化销售数据 salesData.put("2021-01-01", 1000.0); salesData.put("2021-01-02", 1500.0); salesData.put("2021-01-03", 2000.0); salesData.put("2021-01-04", 1200.0); salesData.put("2021-01-05", 1800.0); } // 查询指定日期的销售额 public double getSalesByDate(String date) { if (salesData.containsKey(date)) { return salesData.get(date); } else { return 0.0; } } // 统计指定日期范围内的营业额 public double getTotalSales(String startDate, String endDate) { double totalSales = 0.0; for (String date : salesData.keySet()) { if (date.compareTo(startDate) >= 0 && date.compareTo(endDate) <= 0) { totalSales += salesData.get(date); } } return totalSales; } // 获取所有销售日期 public List<String> getAllSalesDates() { return new ArrayList<>(salesData.keySet()); } } ``` 使用示例: ```java public static void main(String[] args) { SalesStatistics salesStatistics = new SalesStatistics(); // 查询指定日期的销售额 double sales = salesStatistics.getSalesByDate("2021-01-02"); System.out.println("2021-01-02的销售额为:" + sales); // 统计指定日期范围内的营业额 double totalSales = salesStatistics.getTotalSales("2021-01-02", "2021-01-04"); System.out.println("2021-01-02到2021-01-04的营业额为:" + totalSales); // 获取所有销售日期 List<String> salesDates = salesStatistics.getAllSalesDates(); System.out.println("所有销售日期为:" + salesDates); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值