题目链接:FZU2187 【分析】就是扫描线的裸体,本来不会扫描线,特地去学了下。具体看注释。 【AC CODE】890ms
#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
//#include <unordered_set>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
/*扫描线+线段树辅助
把矩形的上下边存起来,并且标记为-1和1;
从下往上每次扫描到一条边的时候计算横坐标覆盖的x长度(用线段树维护)*当前边和下一条边的高度差
就是不重复分一小块面积,全部扫描完就是所有矩形面积的并
线段树记录的是点x~y+1的并,而线段少了个端点,所以加入删除线段x,y的话对应线段树操作x~y-1
*/
typedef LL type;
const int INF = 0x3f3f3f3f, MAXN = 200000+10;
struct NODE{//扫描线段
type l,r,h;
int v;
bool operator<(const NODE &t) const{
return h < t.h;
}
}p[MAXN];
int tol;//线段数量
type pos[MAXN], tmp[MAXN];//离散x坐标,二分找pos
int cnt;//x坐标离散后的数量
int cov[MAXN<<1], lz[MAXN<<1];//cov记录该段完全覆盖次数,lz是cov的lazy标记(可以不用)
type sum2[MAXN<<1], sum1[MAXN<<1], one[MAXN<<1];
//sum2记录被覆盖2次及以上的区间长度,sum1是一次以上的,one只覆盖一次的长度
void init()
{
clc(sum2,0);
clc(sum1,0);
clc(cov,0);
clc(lz,0);
}
inline int id(int x, int y){return x+y|x!=y;}
void push_up(int x, int y, int m)
{
/*计算覆盖一次以及以上的长度*/
int u = id(x,y), l = id(x,m), r = id(m+1,y);
if(cov[u]) sum1[u] = pos[y+1]-pos[x];//完全覆盖
else if(x == y) sum1[u] = 0;//叶子结点
else sum1[u] = sum1[l]+sum1[r];
/*计算覆盖2次以及2次以上的长度*/
if(2 <= cov[u]) sum2[u] = pos[y+1]-pos[x],sum1[u];
else if(x == y) sum2[u] = 0;
else if(1 == cov[u]) sum2[u] = sum1[l]+sum1[r];//当前覆盖了1次只要加上覆盖1次的儿子就是覆盖2次的值
else sum2[u] = sum2[l]+sum2[r];
/*减一下就是只覆盖一次的长度了*/
one[u] = sum1[u]-sum2[u];
}
/*这个向下传递可以不用*/
void push_down(int x, int y, int m)
{
int u = id(x,y);
if(lz[u])
{
int l = id(x,m), r = id(m+1,y);
cov[l] += lz[u], cov[r] += lz[u];
lz[l] += lz[u], lz[r] += lz[u];
lz[u] = 0;
}
}
void update(int x, int y, int ql, int qr, int v)
{
int m = (x+y)>>1;
if(ql <= x && y <= qr)
{
cov[id(x,y)] += v;
push_up(x,y,m);
return;
}
push_down(x,y,m);
if(ql <= m) update(x,m,ql,qr,v);
if(qr > m) update(m+1,y,ql,qr,v);
push_up(x,y,m);
}
int main()
{
#ifdef SHY
freopen("e:\\1.txt", "r", stdin);
#endif
int t,count = 0;
scanf("%d%*c", &t);
while(t--)
{
int n;
scanf("%d%*c", &n);
cnt = tol = 0;
int nn = 0;
rep(i,0,n)
{
type x1,y1,x2,y2;
scanf("%I64d %I64d %I64d %I64d%*c", &x1, &y1, &x2, &y2);
tmp[nn++] = x1, tmp[nn++] = x2;
p[tol].h = y1, p[tol].l = x1, p[tol].r = x2, p[tol++].v = 1;
p[tol].h = y2, p[tol].l = x1, p[tol].r = x2, p[tol++].v = -1;
}
sort(p,p+tol);
sort(tmp,tmp+nn);
pos[cnt++] = tmp[0];
rep(i,1,nn)//tmp去重
{
if(tmp[i] != tmp[i-1]) pos[cnt++] = tmp[i];
}
type ans = 0;
init();
rep(i,0,tol)
{
int x = lower_bound(pos,pos+cnt,p[i].l)-pos, y = lower_bound(pos,pos+cnt,p[i].r)-pos-1;
update(0,cnt-1,x,y,p[i].v);
ans += one[id(0,cnt-1)]*(p[i+1].h-p[i].h);
}
printf("Case %d: %I64d\n",++count, ans);
}
return 0;
}