算是模板题,会了面积交这个应该就会了,正常面积交分为覆盖1次以上,两次以上,这个就分为覆盖1到k次以上就行了。
这个题有点边界问题:是让你求覆盖的点,所以你可以假设一个1*1的正方向表示它的左下角被覆盖,那你读入x2,y2时就让x2++,y2++。这样直接算面积就处理好边界了。
#include<cstdio> #include<iostream> #include<cstdlib> #include<algorithm> #define ll long long #define rep(i, a, b) for(int i = a; i <= b; i++) #define ls num*2 #define rs num*2+1 using namespace std; const int maxn = 3e5 + 1010; int k; ll loc[maxn*2]; struct seg{ ll l, r, h; int flag; bool operator < (const seg &a)const{ return h < a.h; } }line[maxn*2]; struct node{ ll l, r, sum; ll len[12]; }p[maxn*4]; void build(int num, int l, int r){ p[num] = (node){l, r, 0, 0}; if(l == r) return; int mid = (l+r)/2; build(ls, l, mid); build(rs, mid+1, r); } void pushup(int num){ ll int x = p[num].sum; ll l = p[num].l, r = p[num].r; if(p[num].sum){ for(int i = 1; i <= k; i++){ if(p[num].sum >= i) p[num].len[i] = loc[r+1] - loc[l]; else if(l == r) p[num].len[i] = 0; else p[num].len[i] = p[ls].len[i-x] + p[rs].len[i-x]; } } else{ for(int i = 1; i <= k; i++){ if(l == r) p[num].len[i] = 0; else p[num].len[i] = p[ls].len[i] + p[rs].len[i]; } } } void change(int num, ll ul, ll ur, int x){ ll l = p[num].l, r = p[num].r; if(loc[r+1] <= ul || loc[l] >= ur) return; if(loc[r+1] <= ur && loc[l] >= ul){ p[num].sum += x; pushup(num); return; } change(ls, ul, ur, x); change(rs, ul, ur, x); pushup(num); } int main(){ ll x1, x2, y1, y2, n, pos; int cas = 0; int t; scanf("%d",&t); while(t--){ pos = 0; scanf("%lld %d",&n,&k); rep(i, 1, n){ scanf("%lld%lld%lld%lld",&x1, &y1, &x2, &y2); x2++, y2++; loc[++pos] = x1; line[pos] = (seg){x1, x2, y1, 1}; loc[++pos] = x2; line[pos] = (seg){x1, x2, y2, -1}; } n *= 2; sort(line+1, line+1+n); sort(loc+1, loc+1+n); int num = unique(loc+1, loc+1+n) - loc - 1; build(1, 1, num-1); ll ans = 0; rep(i, 1, n-1){ change(1, line[i].l, line[i].r, line[i].flag); ans += p[1].len[k] * (line[i+1].h - line[i].h); } printf("Case %d: %lld\n",++cas, ans); } return 0; }