cdoj 1355 郭大侠与“有何贵干?”

题目传送门


郭大侠与“有何贵干?”

title

连当个值日生也能酷到迷死人,县立学文高中一年二班。这里,有个一入学就引起瞩目的学生,名叫郭大侠。其举手投足都蕴含着一股酷劲,不对,根本酷过头了。因为成为校园焦点,眼前出现了各项威胁。郭大侠的最新潮、最流行的校园生活,自此揭幕。

“在下郭大侠,有何贵干?”

“在一个三维空间里面,有许多个长方体,求恰好覆盖K次的空间的总体积是多少。”

“That's easy!”

真是酷毙了!


Input

第一行包含两个整数N K表示有N个长方体在这个三维空间里,希望知道恰好覆盖K次的体积是多少。
第二到N+1行 每行六个数x1,y1,z1,x2,y2,z2,分别表示这个长方体的左下角坐标,以及这个长方体的右上角的坐标。
1≤N≤100000
1≤K≤10
1≤x1≤x2≤1000000000
1≤y1≤y2≤1000000000
1≤z1≤z2≤3
保证最后答案在longlong范围内

Output

输出一个体积,表示三维空间中恰好覆盖K次的体积是多少。

题解
此题显然是一道道扫描线的题。最开始一看是三维,把我吓死了。后来一看1≤z1≤z2≤3,直接做两个扫描线就好了。如果你不会扫描线,请先做hdu1542Atlantis.
#include <bits/stdc++.h>
using namespace std;

const int Maxn = 100010;
struct data {
	int x, y1, y2, v;
	data(int a = 0, int b = 0, int c = 0, int d = 0) : x(a), y1(b), y2(c), v(d) {}
	bool operator < (const data &A) const {
		return x < A.x;
	}
};
vector <int> Y;
vector <data> op[2];
int N, K, C;

class Sgtree {
protected:
	int dl[Maxn << 3], dr[Maxn << 3], Cover[Maxn << 3], len[Maxn << 3][13];
public:
	void Up(const int &u) {
		int l = dl[u], r = dr[u];
		memset(len[u], 0, sizeof len[u]);
		if (r - l == 1) {
			len[u][min(K + 1, Cover[u])] = Y[r] - Y[l];
		} else {
			int val = Cover[u];
			for (int i = 0; i <= K + 1; ++i)
				len[u][min(val + i, K + 1)] = len[u << 1][i] + len[u << 1 | 1][i];
		}
	}
	
	void Build(int u, int l, int r) {
		dl[u] = l, dr[u] = r, Cover[u] = 0;
		memset(len[u], 0, sizeof len[u]);
		len[u][0] = Y[r] - Y[l];
		if (r - l > 1) {
			int mid = (l + r) >> 1;
			Build(u << 1, l, mid);
			Build(u << 1 | 1, mid, r);
		}
	}
	
	void Update(int u, int x, int y, const int &val) {
		if (x == y) return;
		int l = dl[u], r = dr[u];
		if (x <= l && y >= r) Cover[u] += val;
		else {
			int mid = (l + r) >> 1;
			if (x < mid) Update(u << 1, x, y, val);
			if (y > mid) Update(u << 1 | 1, x, y, val);
		}
		Up(u);
	}
	
	int Query() {
		return len[1][K];
	}
}St;

inline int Rank(const int &v) {
	return lower_bound(Y.begin(), Y.end(), v) - Y.begin();
}

long long Solve(const vector<data> &T) {
	long long ret = 0;
	if (T.size() == 0) return 0LL;
	St.Build(1, 0, C - 1);
	int last = T[0].x, len;
	for (int i = 0; i < T.size(); ++i) {
		len = T[i].x - last;
		ret += (long long)len * St.Query();
		St.Update(1, Rank(T[i].y1), Rank(T[i].y2), T[i].v);
		last = T[i].x;
	}
	return ret;
}

int main() {
	int x1, x2, y1, y2, z1, z2;
	scanf("%d%d", &N, &K);
	for (int i = 0; i < N; ++i) {
		scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2);
		if (z2 - z1 >= 1) {
			Y.push_back(y1); Y.push_back(y2);
			for (int j = z1; j < z2; ++j) {
				op[j - 1].push_back(data(x1, y1, y2, 1));
				op[j - 1].push_back(data(x2, y1, y2, -1));
			}
		}
	}
	sort(Y.begin(), Y.end());
	Y.erase(unique(Y.begin(), Y.end()), Y.end());
	C = Y.size();
	long long ans = 0;
	for (int i = 0; i < 2; ++i) {
		sort(op[i].begin(), op[i].end());
		ans += Solve(op[i]);
	}
	cout << ans << endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值