题意: 有一只熊猫和n个岛,岛分布在二维平面上,坐标为Xi,Yi,岛上有竹子,岛i上的竹子数量为Li,美味值为Wi,每个岛的Wi值唯一。熊猫每天要吃掉一个岛的竹子,并且当天所在的岛上的竹子要比之前所在的岛上的竹子都要美味。熊猫沿着曼哈顿距离在岛之间移动。如果熊猫从岛A移动到岛B走的距离dis>岛B上的竹子的数量,那么熊猫会伤心而死(不吃也是要挂的)。熊猫的初始位置由你选择,问熊猫最多能活几天。存在坐标相同的岛屿。
解法: 把岛屿按W值排序,用类似于求最长上升序列的方法做,设f[i]为位置在岛i时的最长存活天数,那么有f[i] = max(f[j])+1,(dis(i,j)<=L[i])。对于曼哈顿距离的处理,因为到一个点曼哈顿距离小于等于k的区域是一个斜置45度的正方形,那么我们可以通过旋转坐标系使正方形正置,新的坐标为(x`,y`) = (x,y)*(1,1)+(x,y)*(-1,1) = (x-y,x+y)。然后的任务就是写一个数据结构支持查询平面内任意一块正方形区域的最大值,单点插入,那么就是树套树了。由于我第一维选用的线段树,需要对x离散化。
/* Created Time: Monday, October 28, 2013 PM08:08:09 CST */
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int M = 100010;
int n,y1,y2;
struct point {
int x,y,w,c;
void read() {
int a,b;
scanf("%d%d%d%d",&a,&b,&w,&c);
x = a-b;
y = a+b;
}
bool operator < (const point &tt) const {
return w<tt.w;
}
}dot[M];
struct San {
int a[M],n;
void clear() { n = 0;}
void push(int x) { a[n++] = x; }
void doit() { sort(a,a+n); n = unique(a,a+n)-a; }
int operator [] (int x) { return lower_bound(a,a+n,x)-a; }
int size() { return n; }
}sx;
struct Node {
Node *ch[2];
int y,v,mv,r,size;
}memo[M*20],*t[M<<2],*nill;
int tot;
void up(Node *o) {
if (o==nill) return ;
o->mv = max(o->v,max(o->ch[0]->mv,o->ch[1]->mv));
o->size = 1 + o->ch[0]->size + o->ch[1]->size;
}
int ran() { static int ranx = 987456321; return ranx += (ranx<<2)+1; }
void New_node(Node *&o,int y,int v) {
o = &memo[tot++];
o->size = 1;
o->ch[0] = o->ch[1] = nill;
o->v = o->mv = v;
o->y = y;
o->r = ran();
}
// 把小于等于y的部分切到a
void cut(Node *o,Node *&a,Node *&b,int y) {
if (o==nill) {
a = b = nill;
} else if (o->y > y) {
b = o;
cut(o->ch[0],a,b->ch[0],y);
up(b);
} else {
a = o;
cut(o->ch[1],a->ch[1],b,y);
up(a);
}
}
void merge(Node *&o,Node *a,Node *b) {
if (a==nill || b==nill) {
o = (a==nill?b:a);
} else if (a->r > b->r) {
o = a;
merge(o->ch[1],a->ch[1],b);
} else {
o = b;
merge(o->ch[0],a,b->ch[0]);
}
up(o);
}
void insert(Node *&o,int y,int v) {
Node *a,*b,*c;
cut(o,a,b,y);
New_node(c,y,v);
merge(a,a,c);
merge(o,a,b);
}
int query(Node *&o) {
Node *a,*b,*c;
cut(o,a,b,y1-1);
cut(b,b,c,y2);
int ret = b->mv;
merge(a,a,b);
merge(o,a,c);
return ret;
}
void build(int l,int r,int rt) {
t[rt] = nill;
if (l==r) return ;
int mid = l+r>>1;
build(lson);
build(rson);
}
void update(int x,int y,int v,int l,int r,int rt) {
insert(t[rt],y,v);
if (l==r) return ;
int mid = l+r>>1;
if (x<=mid)
update(x,y,v,lson);
else
update(x,y,v,rson);
}
int query(int L,int R,int l,int r,int rt) {
if (L<=l && r<=R)
return query(t[rt]);
int mid = l+r>>1;
int ret = 0;
if (L<=mid)
ret = max(ret,query(L,R,lson));
if (R> mid)
ret = max(ret,query(L,R,rson));
return ret;
}
int work() {
int ret = 1;
sx.doit();
sort(dot,dot+n);
tot = 0;
New_node(nill,0,0);
nill->size = 0;
build(0,sx.size()-1,1);
for (int i = 0; i < n; i ++) {
int c = dot[i].c;
y1 = dot[i].y-c;
y2 = dot[i].y+c;
int x1 = sx[dot[i].x-c];
int x2 = sx[dot[i].x+c];
if (dot[i].x-c>sx.a[x1]) x1 ++;
int v = query(x1,x2,0,sx.size()-1,1)+1;
if (ret<v) ret = v;
update(sx[dot[i].x],dot[i].y,v,0,sx.size()-1,1);
}
return ret;
}
int main() {
int cas,ca=0;
scanf("%d",&cas);
while (cas--) {
scanf("%d",&n);
sx.clear();
for (int i = 0; i < n; i ++) {
dot[i].read();
sx.push(dot[i].x);
}
printf("Case %d: %d\n",++ca,work());
}
return 0;
}