扫描线

扫描线

矩形周长并

例题:USACO5.5.1picture

分两次水平和竖直的扫描,以从左往右扫为例 首先对于所有竖直边按从左到右排序, 再将所有边的上坐标,下坐标离散化(tox[],toy[])

用线段树动态维护当前的线段长度,Ans表示总答案 过程中有用到栈的思想(但并不用打出来) 也就是对于每一个有边的小区间, 每次 遇到矩形的左边如果包含它就+1, 如果+1后值为1 , 说明是左边露出来的一个面,ans+=len 遇到矩形的右边如果包含它就-1 如果减一后值为0, 说明“栈”为空,是右边露出的面,ans+=len

另一种方法: 维护上一次的有标记的总线段长度l1 算出这一次的有标记的总线段长度l2 相减,就是当前变化的线段总长度 detal=l2-l1 detal>0:增加了左边 detal<0:遇到了 右边 反正ans+=abs(detal)

Warning:另外对于两个矩形重叠的左右两个边,应该先加右边矩形的左边再加左边矩形的右边 (可以通过改排序的函数) 因为这种情况是中间没有空隙,不应该算在周长内

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
ID: du331691
PROG: picture
LANG: C++
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
const int maxn=5003;
const int maxx=10003; 
int n;
template<typename T>
void read(T& w)
{
	char r;bool f=false;
	for(r=getchar();(r<48||r>57)&&r!='-';r=getchar());
	if(r=='-')r=getchar(),f=true;
	for(w=0;r>=48&&r<=57;r=getchar())w=w*10+r-48;
	if(f)w=-w;
}

int toxx[maxx*2+1],toyy[maxx*2+1];
int* tox=&toxx[maxx];
int* toy=&toyy[maxx];
struct EDGE
{
	int a,b,p;//a<b
	bool isl;
	void init(int aa,int bb,int pp,bool isll)
	{
		a=aa,b=bb,p=pp;
		isl=isll;
	}
}vedge[maxn*2],hedge[maxn*2];
int vk=0,hk=0;
bool operator<(const EDGE& a,const EDGE& b)
{
	if(a.p!=b.p)return a.p<b.p;
	if(a.isl!=b.isl)return a.isl;
	if(a.a!=b.a)return a.a<b.a;
	if(a.b!=b.b)return a.b<b.b;
	return false;
}

int sx[maxn*2],sy[maxn*2];
int sxk=0,syk=0;
struct RECTANGLE
{
	int ax,ay,bx,by;//lower left, upper right
	void input()
	{
		read(ax),read(ay),read(bx),read(by);
		sx[++sxk]=ax,sx[++sxk]=bx;
		sy[++syk]=ay,sy[++syk]=by;
	}
	void addEdge()
	{
		vedge[++vk].init(ay,by,ax,true);
		vedge[++vk].init(ay,by,bx,false);
		hedge[++hk].init(ax,bx,ay,true);
		hedge[++hk].init(ax,bx,by,false);
	}
}rect[maxn];
int d[maxn*2];
//d[i]存放第i条边区间的长度 
int f[maxn*2],c[maxn*2];
//f[i] 表示在离散化后第i个点以下的一段边的编号 
int idx=0,idy=0;
struct SEQ
{
	int l,r,num,mid,len,sum,tag;
	void build(int numm,int ll,int rr);
	void add(int ll,int rr,int k);
}seq[maxx<<4];
#define root seq[1]
#define lc seq[num<<1]
#define rc seq[num<<1|1]
void SEQ::build(int numm,int ll,int rr)
{
	num=numm,l=ll,r=rr,mid=(l+r)>>1;
	if(l==r)
	{
		len=d[l];
		sum=tag=0;
	}
	else
	{
		lc.build(num<<1,ll,mid);
		rc.build(num<<1|1,mid+1,rr);
		sum=lc.sum+rc.sum;
	}
}
void SEQ::add(int ll,int rr,int k)
{
	if(l==r)
	{
		tag+=k;
		sum=int(bool(tag))*len;
	}
	else
	{
		if(rr<=mid)
			lc.add(ll,rr,k);
		else if(ll>mid)
			rc.add(ll,rr,k);
		else lc.add(ll,mid,k),rc.add(mid+1,rr,k);
		sum=lc.sum+rc.sum;
	}
}
void input()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		rect[i].input();
		rect[i].addEdge();
	}	
}

typedef unsigned int uint;
const uint uinf=4294967295u;
uint ans=0;
void solve()
{
	sort(sy+1,sy+syk+1);
	for(int i=1,last=0;i<=syk;++i)
	{
		if(!toy[sy[i]])
		{
			toy[sy[i]]=++idy;
			f[idy]=idy-1;
			c[idy]=idy;
			d[idy-1]=sy[i]-last;
			last=sy[i];
		}
	}
	root.build(1,1,idy);
	
	sort(vedge+1,vedge+vk+1);
	for(int i=1,last=0;i<=vk;++i)
	{
		if(vedge[i].isl)
			root.add(c[toy[vedge[i].a]],f[toy[vedge[i].b]],1);
		else
			root.add(c[toy[vedge[i].a]],f[toy[vedge[i].b]],-1);
		int detal=abs(root.sum-last);
		ans+=uint(detal);
		last=root.sum;
 	}
 	memset(f,0,sizeof(f));
	memset(c,0,sizeof(c));
	memset(d,0,sizeof(d));
	sort(sx+1,sx+sxk+1);
	for(int i=1,last=0;i<=sxk;++i)
	{
		if(!tox[sx[i]])
		{
			tox[sx[i]]=++idx;
			f[idx]=idx-1;
			c[idx]=idx;
			d[idx-1]=sx[i]-last;
			last=sx[i];
		}
	}
	root.build(1,1,idx);
	sort(hedge+1,hedge+hk+1);
	for(int i=1,last=0;i<=hk;++i)
	{
		if(hedge[i].isl)
			root.add(c[tox[hedge[i].a]],f[tox[hedge[i].b]],1);
		else
			root.add(c[tox[hedge[i].a]],f[tox[hedge[i].b]],-1);
		int detal=abs(root.sum-last);
		ans+=uint(detal);
		last=root.sum;
 	}
}
int main()
{
	freopen("picture.in","r",stdin);
	freopen("picture.out","w",stdout);
	input();
	solve();
	printf("%u\n",ans);
	return 0;
}

参考资料

http://blog.csdn.net/lwt36/article/details/48908031

http://blog.csdn.net/ophunter_lcm/article/details/9129557

http://blog.csdn.net/wukonwukon/article/details/7817061

http://blog.csdn.net/stay_accept/article/details/50527618

http://blog.csdn.net/dgq8211/article/details/8810578

http://blog.csdn.net/lwt36/article/details/48908031

0%