1. 程式人生 > >Usaco Training Section 5.5 Picture

Usaco Training Section 5.5 Picture

求許多矩形的周長並。可以聯想到5.3的Window Area,這道題是求面積並,我們可以用掃描線+排序推一推/線段樹。

這道題我們同樣可以用掃描線來解決。

我的程式碼:

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 2147483647
#define mp make_pair
#define pii pair<int,int>
#define pb push_back
#define r1 rt<<1
#define r2 rt<<1|1
#define ld long double
using namespace std;

inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}

const int N=10005,M=30000;
struct node{
	int x1,x2,y,k;
	bool operator < (const node &b) const{
		if(y!=b.y) return y<b.y;
		else return k>b.k;
	}
}a[N];

struct seg{
	int l,r,len,num,sum,lc,rc;
}st[M<<2];

inline void pushup(int rt){
	if(st[rt].sum>0){
		st[rt].len=st[rt].r-st[rt].l+1;
		st[rt].lc=st[rt].rc=1;
		st[rt].num=1;
	}
	else if(st[rt].l==st[rt].r){
		st[rt].len=st[rt].num=st[rt].lc=st[rt].rc=0;
	}
	else{
		st[rt].len=st[r1].len+st[r2].len;
		st[rt].lc=st[r1].lc;st[rt].rc=st[r2].rc;
		st[rt].num=st[r1].num+st[r2].num-(st[r1].rc&st[r2].lc);
	}
}

inline void build(int l,int r,int rt){
	st[rt].l=l;st[rt].r=r;st[rt].len=st[rt].num=st[rt].sum=st[rt].lc=st[rt].rc=0;
	if(l==r) return;
	int m=(l+r)>>1;
	build(l,m,r1);
	build(m+1,r,r2);
}

inline void update(int l,int r,int c,int rt){
	if(st[rt].l>r||l>st[rt].r) return;
	if(l<=st[rt].l&&st[rt].r<=r){
		st[rt].sum+=c;
		pushup(rt);
		return;
	}
	update(l,r,c,r1);
	update(l,r,c,r2);
	pushup(rt);
}

int main()
{
	freopen("picture.in","r",stdin);
	freopen("picture.out","w",stdout);
	int n=read(),m=0,mx=-inf,mn=inf;
	for(int i=1;i<=n;++i){
		int x1=read(),y1=read(),x2=read(),y2=read();
		mx=max(mx,max(x1,x2));
        mn=min(mn,min(x1,x2));
		a[++m].x1=x1,a[m].x2=x2,a[m].y=y1,a[m].k=1;
		a[++m].x1=x1,a[m].x2=x2,a[m].y=y2,a[m].k=-1;
	}
	sort(a+1,a+m+1);
	build(mn,mx-1,1);
	int ans=0,last=0;
	for(int i=1;i<=m;++i){
		update(a[i].x1,a[i].x2-1,a[i].k,1);
		//橫線
		ans+=abs(st[1].len-last);
		//豎線 
		ans+=(a[i+1].y-a[i].y)*2*st[1].num;
		last=st[1].len;
	}
	printf("%d\n",ans);
	return 0;
}

其實這題可以暴力,排個序推一推。

將橫邊和縱邊分開算,具體直接看程式碼就行了,很好理解。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 2147483647
#define mp make_pair
#define pii pair<int,int>
#define pb push_back
#define r1 rt<<1
#define r2 rt<<1|1
#define ld long double
using namespace std;

inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}

struct node{
	int x1,x2,y,k;
	bool operator < (const node &b) const{
		if(y!=b.y) return y<b.y;
		else return k>b.k;
	}
}a[20005];
struct nod{
	int x1,x2,y1,y2;
}b[20005];
int ans,n,m,f[2][20005];

inline void work(){
	sort(a+1,a+m+1);
	memset(f,0,sizeof(f));
	int x=1;
	while(x<=m){
		int y=a[x].y;
		for(int i=1;i<=20000;++i) f[0][i]=f[1][i];
		while(x<=m&&a[x].y==y){
			for(int i=a[x].x1+10000;i<a[x].x2+10000;++i) f[1][i]+=a[x].k;
			++x;
		}
		for(int i=1;i<=20000;++i){
			if(f[0][i]==0&&f[1][i]>0) ++ans;
			if(f[1][i]==0&&f[0][i]>0) ++ans;
		}
	}
}

int main()
{
	freopen("picture.in","r",stdin);
	freopen("picture.out","w",stdout);
	n=read();m=0;
	for(int i=1;i<=n;++i){
		int x1=read(),y1=read(),x2=read(),y2=read();
		a[++m].x1=x1,a[m].x2=x2,a[m].y=y1,a[m].k=1;
		a[++m].x1=x1,a[m].x2=x2,a[m].y=y2,a[m].k=-1;
		b[i].x1=x1,b[i].y1=y1,b[i].x2=x2,b[i].y2=y2;
	}
	work();
	m=0;
	for(int i=1;i<=n;++i){
		a[++m].x1=b[i].y1,a[m].x2=b[i].y2,a[m].y=b[i].x1,a[m].k=1;
		a[++m].x1=b[i].y1,a[m].x2=b[i].y2,a[m].y=b[i].x2,a[m].k=-1;
	}
	work();
	printf("%d\n",ans);
	return 0;
}

吐槽一下:這題在HDU上也有,但有個坑人的地方,在HDU上這題有多組資料,要修改一下。因為這個wa了好幾次啊!!!