UVA 11983 Weird Advertisement

继续种树~~

之前ZXL童鞋说那俩题不好做,我就先隔过去啦~然后就UVA这个题啦。

和之前差不多,求至少K次覆盖的区域面积(虽然是求点数,但是可以转化为面积哈,因为我用的不是点树哈)。

和3642差不多,这里的K最大是10,所以可以采用一样的方法。关键是怎么找规律,总不能写K个if。。else吧。。

其实想一下就能推出来的,如果当前cover 为 x,那么这个区间覆盖 x + y 次的长度为当前区间子区间覆盖y次的长度和。结点里存的是slen[i]是覆盖次数为i的长度,如果i == K存的是大于等于K的次数。

超过K次的都按K次计算。

注意初始化,0次的话,是总长度,因为这个WA了N次。。。

其他叶节点什么的,注意下细节就好。


P.S. ZXL童鞋的代码比我的短了好多!!!学习之~他的结点存的是slen[i] 覆盖大于等于 i 的次数。这样的话,所有更新一个循环就可以搞定了。

我的:

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 60010;
typedef long long LL;

struct Sline{ int x,y1,y2,flag;};
struct Tnode{				// 一维线段树 
    int l, r, cover, slen[12];
    int len() { return r - l;}
    int mid() { return MID(l,r);}
    bool in(int ll,int rr) { return l >= ll && r <= rr; }
    void lr(int ll,int rr){ l = ll; r = rr;}
};

Tnode 	node[MAX<<2];
Sline 	l[MAX];
int 	y[MAX], cnty, cnt, K;

void add_line(int x1,int y1,int x2,int y2,int &cnt)
{
	l[cnt].x = x1; l[cnt].y1 = y1; l[cnt].y2 = y2;
	l[cnt].flag = 1;
	y[cnt++] = y1;
	l[cnt].x = x2; l[cnt].y1 = y1; l[cnt].y2 = y2;
	l[cnt].flag = -1;
	y[cnt++] = y2;
}

void Build(int t,int l,int r)
{
	node[t].lr(l,r);
	node[t].cover = 0;
	memset(node[t].slen+1, 0, K*sizeof(int));
	node[t].slen[0] = y[node[t].r] - y[node[t].l];
	if( node[t].len() == 1 )
		return ;
	int mid = MID(l,r);
	Build(L(t),l,mid);
	Build(R(t),mid,r);
}

void Updata_len(int t)
{
	int cc = node[t].cover;
	memset(node[t].slen, 0, (K+1)*sizeof(int));
	
	if( cc >= K )
	{
		node[t].slen[K] = y[node[t].r] - y[node[t].l];
		return ;
	}
	if( node[t].len() == 1 )
	{
		node[t].slen[cc] = y[node[t].r] - y[node[t].l];
		return ;
	}
	
	FOR(i, 0, K+1)
	{
		int d = i + cc;
		if( d >= K ) d = K;
		if( d == K )
			node[t].slen[d] += (node[L(t)].slen[i] + node[R(t)].slen[i]);
		else
			node[t].slen[d] = node[L(t)].slen[i] + node[R(t)].slen[i];
	}
	int sum = 0;
	FOR(i, 1, K+1)
		sum += node[t].slen[i];
	
	node[t].slen[0] = y[node[t].r] - y[node[t].l] - sum;
}

void Updata(int t, Sline p)
{
	if( p.y1 <= y[node[t].l] && p.y2 >= y[node[t].r] )
	{
		node[t].cover += p.flag;
		Updata_len(t);
		return ;
	}
	if( node[t].len() == 1 ) return ;
	
	int mid = node[t].mid();
	if( p.y1 < y[mid] )		Updata(L(t), p);
	if( p.y2 > y[mid] ) 	Updata(R(t), p);
	
	Updata_len(t);
}
bool cmp(Sline a, Sline b)
{
	if( a.x == b.x )
		return a.flag > b.flag;
	return a.x < b.x;
}

LL solve(int n)
{
	LL ans = 0;
	sort(y, y+n);
	cnty = unique(y, y+n) - y;
	sort(l, l+n, cmp);
	
	Build(1, 0, cnty-1);
	
	Updata(1, l[0]);
	FOR(i, 1, n)
	{
		ans += node[1].slen[K] * 1ll * (l[i].x - l[i-1].x);
		Updata(1, l[i]);
	}
	return ans;
}
int main()
{
	int ind = 1, ncases, n, x1, y1, x2, y2;
	
	scanf("%d", &ncases);
	
	while( ncases-- )
	{
		cnt = 0;
		scanf("%d%d", &n, &K);
		
		FOR(i, 0, n)
		{
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			x2++; y2++;
			add_line(x1, y1, x2, y2, cnt);
		}
		
		if( K > n )
		{
			printf("Case %d: 0\n", ind++);
			continue;
		}
		
		LL ans = solve(cnt);
		
		printf("Case %d: %lld\n", ind++, ans);
	}	

return 0;
}


改进后的:Build里面也不用给slen[0]赋初值了

#include <set>
#include <map>
#include <queue>
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
#include <string.h>
#include <string>
#include <algorithm>
#define MID(x,y) ( ( x + y ) >> 1 )
#define L(x) ( x << 1 )
#define R(x) ( x << 1 | 1 )
#define FOR(i,s,t) for(int i=(s); i<(t); i++)
#define BUG puts("here!!!")
#define STOP system("pause")
#define file_r(x) freopen(x, "r", stdin)
#define file_w(x) freopen(x, "w", stdout)

using namespace std;

const int MAX = 60010;
typedef long long LL;

struct Sline{ int x,y1,y2,flag;};
struct Tnode{				// 一维线段树 
    int l, r, cover, slen[12];
    int len() { return r - l;}
    int mid() { return MID(l,r);}
    bool in(int ll,int rr) { return l >= ll && r <= rr; }
    void lr(int ll,int rr){ l = ll; r = rr;}
};

Tnode 	node[MAX<<2];
Sline 	l[MAX];
int 	y[MAX], cnty, cnt, K;

void add_line(int x1,int y1,int x2,int y2,int &cnt)
{
	l[cnt].x = x1; l[cnt].y1 = y1; l[cnt].y2 = y2;
	l[cnt].flag = 1;
	y[cnt++] = y1;
	l[cnt].x = x2; l[cnt].y1 = y1; l[cnt].y2 = y2;
	l[cnt].flag = -1;
	y[cnt++] = y2;
}

void Build(int t,int l,int r)
{
	node[t].lr(l,r);
	node[t].cover = 0;
	memset(node[t].slen+1, 0, K*sizeof(int));
//	node[t].slen[0] = y[node[t].r] - y[node[t].l];
	if( node[t].len() == 1 )
		return ;
	int mid = MID(l,r);
	Build(L(t),l,mid);
	Build(R(t),mid,r);
}

void Updata_len(int t)
{
	int cc = node[t].cover;
	FOR(i, 0, K+1)
	{
		if( cc >= i )
			node[t].slen[i] = y[node[t].r] - y[node[t].l];
		else
			if( node[t].len() == 1 )
				node[t].slen[i] = 0;
			else
				node[t].slen[i] = node[L(t)].slen[i-cc] + node[R(t)].slen[i-cc];
	}
}

void Updata(int t, Sline p)
{
	if( p.y1 <= y[node[t].l] && p.y2 >= y[node[t].r] )
	{
		node[t].cover += p.flag;
		Updata_len(t);
		return ;
	}
	if( node[t].len() == 1 ) return ;
	
	int mid = node[t].mid();
	if( p.y1 < y[mid] )		Updata(L(t), p);
	if( p.y2 > y[mid] ) 	Updata(R(t), p);
	
	Updata_len(t);
}
bool cmp(Sline a, Sline b)
{
	if( a.x == b.x )
		return a.flag > b.flag;
	return a.x < b.x;
}

LL solve(int n)
{
	LL ans = 0;
	sort(y, y+n);
	cnty = unique(y, y+n) - y;
	sort(l, l+n, cmp);
	
	Build(1, 0, cnty-1);
	
	Updata(1, l[0]);
	FOR(i, 1, n)
	{
		ans += node[1].slen[K] * 1ll * (l[i].x - l[i-1].x);
		Updata(1, l[i]);
	}
	return ans;
}
int main()
{
	int ind = 1, ncases, n, x1, y1, x2, y2;
	
	scanf("%d", &ncases);
	
	while( ncases-- )
	{
		cnt = 0;
		scanf("%d%d", &n, &K);
		
		FOR(i, 0, n)
		{
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			x2++; y2++;
			add_line(x1, y1, x2, y2, cnt);
		}
		
		if( K > n )
		{
			printf("Case %d: 0\n", ind++);
			continue;
		}
		
		LL ans = solve(cnt);
		
		printf("Case %d: %lld\n", ind++, ans);
	}	

return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值