poj 3695 Rectangles 线段树扫描线 or 容斥原理

POJ 3695

题意 : 求矩形的面积并


扫描线 : 直接线段树扫描线会超时,因为询问实在是太多了,必须要离散化,离散化如果还超时的话只能继续各种优化了,
这里我把x边都预处理一下,就避免了询问里再排序


容斥原理 :对于每一次询问处理出重合 1 到 r 次的面积(r 为每次询问的矩形数) , 然后进行容斥原理,这里我处理重合面积的方法是这样的,
对于前两个矩形如果重合,就构造个重合部分的矩形继续往下搜


线段树

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
struct REC{
	int x1,y1,x2,y2;
}rec[22];
struct seg{
	int x1,x2,y,h,flag,id;
	seg(){}
	seg(int x1,int x2,int h,int flag,int id) : x1(x1), x2(x2), h(h), flag(flag), id(id) {}
	bool operator < (const seg &a) const {
		return h<a.h;
	}
}ss[55];
struct PP{
	int x,id;
	bool operator < (const PP &a) const
	{
		return x<a.x;
	}
}ax[55];
int sum[11111],cnt[11111],xx[111],vis[22];
void push_up(int rt,int l,int r)
{
	if(cnt[rt])
		sum[rt] = xx[r+1]-xx[l];
	else if(l==r)
		sum[rt] = 0;
	else
		sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void update(int rt,int l,int r,int L,int R,int flag)
{
	if( L<=l && R>=r)
	{
		cnt[rt]+=flag;
		push_up(rt,l,r);
		return ;
	}
	int mid = (l+r)>>1;
	if(L<=mid)
		update(lson,L,R,flag);
	if(R>mid)
		update(rson,L,R,flag);
	push_up(rt,l,r);
}
int bin(int x,int l,int r)
{
	while(l<=r)
	{
		int mid = (l+r)>>1;
		if(xx[mid] == x)
			return mid;
		if(xx[mid] > x)
			r = mid-1;
		else
			l = mid+1;
	}
}
void init()
{
	memset(cnt,0,sizeof(cnt));
	memset(sum,0,sizeof(sum));
}
int main()
{
	int n,m,i,x,r,j;
	int cas = 1;
	while(scanf("%d%d", &n, &m)!=-1 && n)
	{
		printf("Case %d:\n", cas++);
		int d = 0;
		for(i = 1;i <= n ; i++)
		{
			scanf("%d%d%d%d", &rec[i].x1,&rec[i].y1,&rec[i].x2,&rec[i].y2);
			ax[d].x = rec[i].x1;
			ax[d].id = i;
			ss[d++] = seg(rec[i].x1,rec[i].x2,rec[i].y1,1,i);
			ax[d].x = rec[i].x2;
			ax[d].id = i;
			ss[d++] = seg(rec[i].x1,rec[i].x2,rec[i].y2,-1,i);
		}
		sort(ss,ss+d);
		sort(ax,ax+d);
		int dd = 1;
		for(i = 1;i < d; i++)
			if(ax[i].x!=ax[i-1].x)
				ax[dd++] = ax[i];
		for(i = 1;i <= m ;i++)
		{
			for(j = 1;j <= n; j++)
				vis[j] = 0;
			scanf("%d", &r);
			int mm = 0;
			while(r--)
			{
				scanf("%d", &x);
				vis[x]++;
			}
			int k = 0;
			for(j = 0;j < dd; j++)
			{
				if(!vis[ax[j].id])
					continue;
				xx[k++] = ax[j].x;
			}
			int ans = 0;
			int pre = 0;
			int preh = -1;
			for(j = 0;j < d; j++)
			{
				if(!vis[ss[j].id])
					continue;
				int l = bin(ss[j].x1,0,k-1);
				int r = bin(ss[j].x2,0,k-1)-1;
				update(1,0,k-1,l,r,ss[j].flag);
			//	printf("sum[1] = %d\n",sum[1]);
				if(preh>=0)
				ans += pre*(ss[j].h-preh);
				preh = ss[j].h;
				pre = sum[1];
			}
			printf("Query %d: %d\n",i,ans);
		}
		puts("");
	}
	return 0;
}

容斥原理

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
using namespace std;

struct REC{
	int x1,x2,y1,y2;
}rec[22],cur[22],d[22];
int change[22] , top;
void find(int now,int num,int tot)
{
	int i;
	if(num == tot)
	{
		if(tot==1)
		{
			change[tot] += (d[0].x2-d[0].x1)*(d[0].y2-d[0].y1);
			find(now,num,tot+1);
			return ;
		}
		int mx1 = max(d[tot-1].x1,d[tot-2].x1);
		int mx2 = min(d[tot-1].x2,d[tot-2].x2);
		int my1 = max(d[tot-1].y1,d[tot-2].y1);
		int my2 = min(d[tot-1].y2,d[tot-2].y2);
		if(mx1 < mx2 && my1 < my2)
		{
			d[tot-1].x1 = mx1;
			d[tot-1].x2 = mx2;
			d[tot-1].y1 = my1;
			d[tot-1].y2 = my2;
			change[tot] += (mx2-mx1)*(my2-my1);
		//	printf("tot = %d\n", tot);
		//	printf("%d %d %d %d\n",mx1,my1,mx2,my2);
			find(now,num,tot+1);
		}
	}
	else
		for(i = now;i < top; i++)
		{
			d[num] = cur[i];
			find(i+1,num+1,tot);
		}
}
int main()
{
	int n,m,i,j,r,x;
	int cas = 1;
	while(scanf("%d%d", &n , &m )!=-1 && n)
	{
		printf("Case %d:\n", cas++);
		for(i = 1;i <= n; i ++)
			scanf("%d%d%d%d", &rec[i].x1, &rec[i].y1, &rec[i].x2, &rec[i].y2);
		for(i = 1;i <= m; i++)
		{
			scanf("%d", &r);
			for(j = 0;j < r; j++)
			{
				scanf("%d", &x);
				cur[j] = rec[x];
			}
			top = r;
			for(j = 1;j <= r; j++)
				change[j] = 0;
			find(0,0,1);
			int ans = 0;
			for(j = 1;j <= r; j++)
			{
			//	printf("change[%d] = %d\n",j , change[j]);
				if(j&1)
					ans += change[j];
				else
					ans -= change[j];
			}
			printf("Query %d: %d\n",i, ans);
		}
		puts("");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值