继续种树~~
之前ZXL童鞋说那俩题不好做,我就先隔过去啦~然后就UVA这个题啦。
和之前差不多,求至少K次覆盖的区域面积(虽然是求点数,但是可以转化为面积哈,因为我用的不是点树哈)。
和3642差不多,这里的K最大是10,所以可以采用一样的方法。关键是怎么找规律,总不能写K个if。。else吧。。
其实想一下就能推出来的,如果当前cover 为 x,那么这个区间覆盖 x + y 次的长度为当前区间子区间覆盖y次的长度和。结点里存的是slen[i]是覆盖次数为i的长度,如果i == K存的是大于等于K的次数。
超过K次的都按K次计算。
注意初始化,0次的话,是总长度,因为这个WA了N次。。。
其他叶节点什么的,注意下细节就好。
P.S. ZXL童鞋的代码比我的短了好多!!!学习之~他的结点存的是slen[i] 覆盖大于等于 i 的次数。这样的话,所有更新一个循环就可以搞定了。
我的:
#include <set> #include <map> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define FOR(i,s,t) for(int i=(s); i<(t); i++) #define BUG puts("here!!!") #define STOP system("pause") #define file_r(x) freopen(x, "r", stdin) #define file_w(x) freopen(x, "w", stdout) using namespace std; const int MAX = 60010; typedef long long LL; struct Sline{ int x,y1,y2,flag;}; struct Tnode{ // 一维线段树 int l, r, cover, slen[12]; int len() { return r - l;} int mid() { return MID(l,r);} bool in(int ll,int rr) { return l >= ll && r <= rr; } void lr(int ll,int rr){ l = ll; r = rr;} }; Tnode node[MAX<<2]; Sline l[MAX]; int y[MAX], cnty, cnt, K; void add_line(int x1,int y1,int x2,int y2,int &cnt) { l[cnt].x = x1; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt].flag = 1; y[cnt++] = y1; l[cnt].x = x2; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt].flag = -1; y[cnt++] = y2; } void Build(int t,int l,int r) { node[t].lr(l,r); node[t].cover = 0; memset(node[t].slen+1, 0, K*sizeof(int)); node[t].slen[0] = y[node[t].r] - y[node[t].l]; if( node[t].len() == 1 ) return ; int mid = MID(l,r); Build(L(t),l,mid); Build(R(t),mid,r); } void Updata_len(int t) { int cc = node[t].cover; memset(node[t].slen, 0, (K+1)*sizeof(int)); if( cc >= K ) { node[t].slen[K] = y[node[t].r] - y[node[t].l]; return ; } if( node[t].len() == 1 ) { node[t].slen[cc] = y[node[t].r] - y[node[t].l]; return ; } FOR(i, 0, K+1) { int d = i + cc; if( d >= K ) d = K; if( d == K ) node[t].slen[d] += (node[L(t)].slen[i] + node[R(t)].slen[i]); else node[t].slen[d] = node[L(t)].slen[i] + node[R(t)].slen[i]; } int sum = 0; FOR(i, 1, K+1) sum += node[t].slen[i]; node[t].slen[0] = y[node[t].r] - y[node[t].l] - sum; } void Updata(int t, Sline p) { if( p.y1 <= y[node[t].l] && p.y2 >= y[node[t].r] ) { node[t].cover += p.flag; Updata_len(t); return ; } if( node[t].len() == 1 ) return ; int mid = node[t].mid(); if( p.y1 < y[mid] ) Updata(L(t), p); if( p.y2 > y[mid] ) Updata(R(t), p); Updata_len(t); } bool cmp(Sline a, Sline b) { if( a.x == b.x ) return a.flag > b.flag; return a.x < b.x; } LL solve(int n) { LL ans = 0; sort(y, y+n); cnty = unique(y, y+n) - y; sort(l, l+n, cmp); Build(1, 0, cnty-1); Updata(1, l[0]); FOR(i, 1, n) { ans += node[1].slen[K] * 1ll * (l[i].x - l[i-1].x); Updata(1, l[i]); } return ans; } int main() { int ind = 1, ncases, n, x1, y1, x2, y2; scanf("%d", &ncases); while( ncases-- ) { cnt = 0; scanf("%d%d", &n, &K); FOR(i, 0, n) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); x2++; y2++; add_line(x1, y1, x2, y2, cnt); } if( K > n ) { printf("Case %d: 0\n", ind++); continue; } LL ans = solve(cnt); printf("Case %d: %lld\n", ind++, ans); } return 0; }
改进后的:Build里面也不用给slen[0]赋初值了
#include <set> #include <map> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define FOR(i,s,t) for(int i=(s); i<(t); i++) #define BUG puts("here!!!") #define STOP system("pause") #define file_r(x) freopen(x, "r", stdin) #define file_w(x) freopen(x, "w", stdout) using namespace std; const int MAX = 60010; typedef long long LL; struct Sline{ int x,y1,y2,flag;}; struct Tnode{ // 一维线段树 int l, r, cover, slen[12]; int len() { return r - l;} int mid() { return MID(l,r);} bool in(int ll,int rr) { return l >= ll && r <= rr; } void lr(int ll,int rr){ l = ll; r = rr;} }; Tnode node[MAX<<2]; Sline l[MAX]; int y[MAX], cnty, cnt, K; void add_line(int x1,int y1,int x2,int y2,int &cnt) { l[cnt].x = x1; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt].flag = 1; y[cnt++] = y1; l[cnt].x = x2; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt].flag = -1; y[cnt++] = y2; } void Build(int t,int l,int r) { node[t].lr(l,r); node[t].cover = 0; memset(node[t].slen+1, 0, K*sizeof(int)); // node[t].slen[0] = y[node[t].r] - y[node[t].l]; if( node[t].len() == 1 ) return ; int mid = MID(l,r); Build(L(t),l,mid); Build(R(t),mid,r); } void Updata_len(int t) { int cc = node[t].cover; FOR(i, 0, K+1) { if( cc >= i ) node[t].slen[i] = y[node[t].r] - y[node[t].l]; else if( node[t].len() == 1 ) node[t].slen[i] = 0; else node[t].slen[i] = node[L(t)].slen[i-cc] + node[R(t)].slen[i-cc]; } } void Updata(int t, Sline p) { if( p.y1 <= y[node[t].l] && p.y2 >= y[node[t].r] ) { node[t].cover += p.flag; Updata_len(t); return ; } if( node[t].len() == 1 ) return ; int mid = node[t].mid(); if( p.y1 < y[mid] ) Updata(L(t), p); if( p.y2 > y[mid] ) Updata(R(t), p); Updata_len(t); } bool cmp(Sline a, Sline b) { if( a.x == b.x ) return a.flag > b.flag; return a.x < b.x; } LL solve(int n) { LL ans = 0; sort(y, y+n); cnty = unique(y, y+n) - y; sort(l, l+n, cmp); Build(1, 0, cnty-1); Updata(1, l[0]); FOR(i, 1, n) { ans += node[1].slen[K] * 1ll * (l[i].x - l[i-1].x); Updata(1, l[i]); } return ans; } int main() { int ind = 1, ncases, n, x1, y1, x2, y2; scanf("%d", &ncases); while( ncases-- ) { cnt = 0; scanf("%d%d", &n, &K); FOR(i, 0, n) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); x2++; y2++; add_line(x1, y1, x2, y2, cnt); } if( K > n ) { printf("Case %d: 0\n", ind++); continue; } LL ans = solve(cnt); printf("Case %d: %lld\n", ind++, ans); } return 0; }