[USACO5.5]矩形周长Picture(线段树扫描线)

我没法写出这么详尽的题解,传送门:矩形周长

很经典的一个题目,将线段之间的关系处理得很好。算是学到了一种黑科技。其实还可以离散化。(主要是题解写得好)

#include
#include
#include
#include
using namespace std;
#define cc(i) cover_cnt[(i)]
#define acc(i) all_cover_cnt[(i)]
const int MAXN=10005;

int N,tot=0;
int rt=0,np=0;
int lc[MAXN<<2];
int rc[MAXN<<2];
int len[MAXN<<2];
int lfg[MAXN<<2];
int rfg[MAXN<<2];
int cover_cnt[MAXN<<2];
int all_cover_cnt[MAXN<<2];


struct data{
	int l,r,h,flag;
	friend bool operator<(data a,data b){
		if(a.h==b.h)return a.flag>b.flag;
		return a.h>1;
	build(lc[now],L,mid);
	build(rc[now],mid+1,R);
}
void pushup(int now,int L,int R){
	if(acc(now)){//整个被覆盖 
		cc(now)=1;len[now]=R-L+1;//不相交覆盖的算作一个 
		lfg[now]=1;rfg[now]=1;//左右均被覆盖到 
	}
	else if(L==R){
		cc(now)=0;len[now]=0;//一个单点是没有长度的 
		lfg[now]=0;rfg[now]=0;
	}
	else{
		cc(now)=cc(lc[now])+cc(rc[now]); 
		if(rfg[lc[now]]&&lfg[rc[now]])cc(now)--;//特判是否有相交 
		len[now]=len[lc[now]]+len[rc[now]];
		lfg[now]=lfg[lc[now]];
		rfg[now]=rfg[rc[now]];
	}
}
void update(int now,int L,int R,int i,int j,int d){
	if(i<=L&&R<=j){
		acc(now)+=d;//整个被覆盖 
		pushup(now,L,R);
		return;
	}
	int mid=(L+R)>>1;
	if(i<=mid)update(lc[now],L,mid,i,j,d);
	if(mid>N;
	for(int i=1;i<=N;i++){
		cin>>x1>>y1>>x2>>y2;
		MX=max(MX,x1);MX=max(MX,x2);
		MN=min(MN,x1);MN=min(MN,x2);
		a[++tot]=(data){x1,x2,y1,1};//下边 
		a[++tot]=(data){x1,x2,y2,-1};//上边 
	}
	if(MN<=0){//保证所有的坐标为正值。其实可以离散化 
		for(int i=1;i<=tot;i++){
			a[i].l+=-MN+1;
			a[i].r+=-MN+1;
		}
		MX+=-MN;//细节 
	}
	sort(a+1,a+1+tot);//按照高度排序 
	build(rt,1,MX);
	int ans=0,last=0;
	for(int i=1;i<=tot;i++){
		update(rt,1,MX,a[i].l,a[i].r-1,a[i].flag);//右端点的细节 
		while(a[i].h==a[i+1].h&&a[i].flag==a[i+1].flag){
			i++; 
			update(rt,1,MX,a[i].l,a[i].r-1,a[i].flag);
		}
		ans+=abs(len[rt]-last);//更新前后之差 
		ans+=cc(rt)*2*(a[i+1].h-a[i].h);//不相交的覆盖次数*2*高度差 
		last=len[rt];//更新last            每次不相交覆盖都有两竖边 
	}
	cout<

 

你可能感兴趣的:(数据结构,USACO)