ZOJ_3511
一种可行的思路就是如果我们把切蛋糕的方案排个序,每次切下来一块就算一下这块的边长,而且这一块必须不会再被切到。
为了实现上面的思路,我们不妨把每次切的方案记作(x,y),且x<y,那么很显然有一种排序方式是一定符合要求的,即按y-x的值由小到大排序。
接下来的问题就是怎么算边长了。实际上可以发现边长的数量是等于点的数量,于是我们不妨用线段树记录一下x、y之间点的数量,每切一刀就相当于把x+1、y-1之间所有的点删掉了,这样我们只要查询x、y之间点的数量,就可以将其作为我们当前切下来的这块蛋糕边的数量。最后蛋糕还剩一块没有统计,再看一下最后还剩多少个点就行了。
#include<stdio.h> #include<string.h> #include<stdlib.h> #define MAXD 100010 struct Cut { int x, y; }cut[MAXD]; int N, M, num[4 * MAXD]; int cmp(const void *_p, const void *_q) { Cut *p = (Cut *)_p, *q = (Cut *)_q; return p->y - p->x < q->y - q->x ? -1 : 1; } void update(int cur) { num[cur] = num[cur << 1] + num[(cur << 1) | 1]; } void build(int cur, int x, int y) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; num[cur] = y - x + 1; if(x == y) return ; build(ls, x, mid); build(rs, mid + 1, y); } void init() { int i, x, y; for(i = 1; i <= M; i ++) { scanf("%d%d", &x, &y); if(x < y) cut[i].x = x, cut[i].y = y; else cut[i].x = y, cut[i].y = x; } qsort(cut + 1, M, sizeof(cut[0]), cmp); build(1, 1, N); } int query(int cur, int x, int y, int s, int t) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; if(x >= s && y <= t) return num[cur]; if(mid >= t) return query(ls, x, mid, s, t); else if(mid + 1 <= s) return query(rs, mid + 1, y, s, t); else return query(ls, x, mid, s, t) + query(rs, mid + 1, y, s, t); } void refresh(int cur, int x, int y, int s, int t) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; if(x >= s && y <= t) { num[cur] = 0; return ; } if(mid >= s) refresh(ls, x, mid, s, t); if(mid + 1 <= t) refresh(rs, mid + 1, y, s, t); update(cur); } void solve() { int i, j, k, ans = 0; for(i = 1; i <= M; i ++) { k = query(1, 1, N, cut[i].x, cut[i].y); if(k > ans) ans = k; refresh(1, 1, N, cut[i].x + 1, cut[i].y - 1); } if(num[1] > ans) ans = num[1]; printf("%d\n", ans); } int main() { while(scanf("%d%d", &N, &M) == 2) { if(M == 0) printf("%d\n", N); else { init(); solve(); } } return 0; }