2016 UESTC Training for Data Structures F - 郭大侠与“有何贵干?” CDOJ 1335 线段树 扫描线 离散化

F - 郭大侠与“有何贵干?”

就是给一个三维空间,和N个长方体,问覆盖K次的体积

xy都是1e9,但是z[1,3],所以可以把这个分为两个二维平面,求被覆盖K次的面积,最后加一下就行

然后就转换成了二维平面求覆盖k次的面积,k属于[1,10],然后就是,先离散化,然后线段树+扫描线

具体做法,就是,线段树节点开一个sum[12]的数组,然后i<=10时,sum[i]表示覆盖i次的面积,当然,sum[11]表示覆盖11次及以上的面积,

顺带一提,我这里依旧是用的闭区间的线段树,所以我存的是点,但是题目里给的是线段,所以我程序里要--y2;,当然,这依旧有B题那种的信息丢失的问题,然后也是需要一个tag,表示这个区间的中间丢失部分的被覆盖次数,

后面就是扫描线扫过去统计就行啦,另,这题只能建一棵线段树,使用两次,建两棵会MLE

 

刚开始时我也在想为什么扫描线能做,后来想到了一个感觉正确的证明,就是用数学归纳法,首先我更新到叶子节点的时候,我会把那个节点的信息清空,然后赋上新的信息,所以我的叶子节点一定是正确的,

然后我这个节点的lazy,表示下面的区间又被覆盖了lazy次,由于这种题的特性,显然lazy>=0的,所以不用考虑变负的情况,然后,由于我的叶子节点是正确的,所以我可以根据我的叶子节点的信息和它的父区间的lazytag,然后求出它的父区间的信息,这样,它的父区间的信息也就是正确的,然后我就可以依次往上push_up,所以上面就一定是正确的,所以就证明结束啦,所以就对啦,

之前我也在想如果覆盖10000次,再慢慢减掉这一万次,不会出错吗,后来发现,由于lazy的存在,然后就保证我们在减下去的时候,也会得到对的答案

 

呃,别的呢,还有什么呢,还有就是push_up的过程吧,把这个地方理顺了,其他地方都不难写,具体可以看代码吧,感觉我代码里还是写的清楚的,其实就是按正常的逻辑走就行,要注意的一个问题就是你的覆盖为0的次数会随着被覆盖而减少,也随着覆盖取消而增加,这个需要考虑到(好像在正常的过程中就能把它处理好),反正我就是按普通的思路来想的,建树初始化时也是把sum[0]初始化成区间长度

 

总结来说就是,push_up比较乱,还有就是代码长,理顺了,写就行,

另外感觉就是这题如果是单点更新的话就是裸的树状数组套主席树?虽然在网上学习了一发这个姿势之后发现这题还是用线段树扫描线来做


代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define maxn 100005
#define lid (id<<1)
#define rid ((id<<1)|1)
int N, K;
int data_x[2 * maxn], data_y[2 * maxn], num_x = 1, num_y = 1;
struct Edge
{
	int y1, y2, x, val;
	void make(int x, int y1, int y2, int val)
	{
		this->y1 = y1, this->y2 = y2, this->x = x, this->val = val;
	}
}edge1[maxn * 2], edge2[maxn * 2];
struct segtree
{
	int l, r;
	int sum[12], lazy, ans, tag;
}tr[maxn * 8];
bool cmp(Edge a, Edge b)
{
	return a.x < b.x;
}
void bulid(int id, int l, int r)
{
	tr[id].l = l; tr[id].r = r;
	memset(tr[id].sum, 0, sizeof(int) * 12);
	tr[id].sum[0] = data_y[tr[id].r] - data_y[tr[id].l] + 1;
	tr[id].lazy = 0, tr[id].ans = 0, tr[id].tag = 0;
	if (l == r)
		return;
	int mid = (l + r) >> 1;
	bulid(lid, l, mid);
	bulid(rid, mid + 1, r);
}
void push_up(int id)
{
	if (tr[id].l == tr[id].r)
	{
		memset(tr[id].sum, 0, sizeof(int) * 12);
		int x = min(K + 1, tr[id].lazy);
		tr[id].sum[x] = 1;
		if (x == K)
			tr[id].ans = 1;
		return;
	}
	for (int i = 0; i <= K + 1; ++i)
	{
		int x = min(K + 1, i + tr[id].lazy);
		if (x==K+1)
			tr[id].sum[x] += tr[lid].sum[i] + tr[rid].sum[i];
		else
			tr[id].sum[x] = tr[lid].sum[i] + tr[rid].sum[i];
	}
	int x = min(K + 2, tr[id].lazy);
	for (int i = 0; i < x; ++i)
		tr[id].sum[i] = 0;
	x = min(K + 1, tr[id].tag);
	tr[id].sum[x] += data_y[tr[rid].l] - data_y[tr[lid].r] - 1;
	tr[id].ans = tr[id].sum[K];
}
void update(int id, int l, int r, int v)
{
	if (l == tr[id].l&&tr[id].r == r)
	{
		tr[id].lazy += v;
		tr[id].tag += v;
		push_up(id);
		return;
	}
	int mid = (tr[id].l + tr[id].r) >> 1;
	if (r <= mid) update(lid, l, r, v);
	else if (l > mid) update(rid, l, r, v);
	else
	{
		tr[id].tag += v;
		update(lid, l, mid, v);
		update(rid, mid + 1, r, v);
	}
	push_up(id);
}
int main()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	scanf("%d%d", &N, &K);
	int x1, y1, z1, x2, y2, z2;
	int num1 = 0, num2 = 0, x_num = 0, y_num = 0;
	ll ans = 0;
	bool f = 0;
	for (int i = 0; i < N; ++i)
	{
		scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2);
		if (z1 == z2 || x1 == x2 || y1 == y2)
			continue;
		--y2;
		data_x[num_x++] = x1;
		data_x[num_x++] = x2;
		data_y[num_y++] = y1;
		data_y[num_y++] = y2;
		if (z1 == 1)
		{
			if (z2 == 2)
			{
				edge1[num1++].make(x1, y1, y2, 1);
				edge1[num1++].make(x2, y1, y2, -1);
			}
			else if (z2 == 3)
			{
				edge1[num1++].make(x1, y1, y2, 1);
				edge1[num1++].make(x2, y1, y2, -1);
				edge2[num2++].make(x1, y1, y2, 1);
				edge2[num2++].make(x2, y1, y2, -1);
			}
		}
		if (z1 == 2)
		{
			if (z2 == 3)
			{
				edge2[num2++].make(x1, y1, y2, 1);
				edge2[num2++].make(x2, y1, y2, -1);
			}
		}
	}
	data_x[num_x++] = 1000000001;
	sort(edge1, edge1 + num1, cmp), sort(edge2, edge2 + num2, cmp);
	sort(data_x, data_x + num_x), sort(data_y, data_y + num_y);
	num_x = unique(data_x, data_x + num_x) - data_x, num_y = unique(data_y, data_y + num_y) - data_y;
	for (int i = 0; i < num1; ++i)
	{
		edge1[i].x = lower_bound(data_x, data_x + num_x, edge1[i].x) - data_x;
		edge1[i].y1 = lower_bound(data_y, data_y + num_y, edge1[i].y1) - data_y;
		edge1[i].y2 = lower_bound(data_y, data_y + num_y, edge1[i].y2) - data_y;
	}
	for (int i = 0; i < num2; ++i)
	{
		edge2[i].x = lower_bound(data_x, data_x + num_x, edge2[i].x) - data_x;
		edge2[i].y1 = lower_bound(data_y, data_y + num_y, edge2[i].y1) - data_y;
		edge2[i].y2 = lower_bound(data_y, data_y + num_y, edge2[i].y2) - data_y;
	}
	if (num_y <= 1)
	{
		printf("0\n");
		//system("pause");
		//while (1);
		return 0;
	}
	bulid(1, 1, num_y - 1); 
	for (int i = 1, t = 0; i < num_x - 1&&t < num1; ++i)
	{
		while (edge1[t].x == i&&t < num1)
		{
			update(1, edge1[t].y1, edge1[t].y2, edge1[t].val);
// 
			++t;
		}
		ans += (ll)tr[1].ans*(ll)(data_x[i + 1] - data_x[i]);;
	}
	bulid(1, 1, num_y - 1);
	for (int i = 1, t = 0; i < num_x - 1&&t < num2; ++i)
	{
		while (edge2[t].x == i&&t < num2)
		{
			update(1, edge2[t].y1, edge2[t].y2, edge2[t].val);
			++t;
		}
		ans += (ll)tr[1].ans*(ll)(data_x[i + 1] - data_x[i]);
	}
	printf("%lld\n", ans);
	//system("pause");
	//while (1);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值