题目链接: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; }