首页 > 代码库 > 【BZOJ 3476】 线段树===
【BZOJ 3476】 线段树===
59 懒惰的奶牛
贝西所在的牧场,散落着 N 堆牧草,其中第 i 堆牧草在 ( Xi,Yi ) 的位置,数量有 Ai 个单位。
贝西从家移动到某一堆牧草的时候,只能沿坐标轴朝正北、正东、正西、正南这四个方向移
动,所以计算贝西和牧草间的距离时,应采用“曼哈顿距离”—— (x,y ) 和 (x ′,y ′) 之间的距离为
|x ? x ′ | + |y ? y ′ |。例如贝西的家在 (0.5, 0.3),有一堆牧草在 (3, 2),那么它们之间的距离就是 4.2。
贝西懒得走动,她想请你为它寻找一个最好的位置作为家,这个家附近距离不超过 K 的牧草数
量之和是最大的。注意家的坐标可以不是整数,也可以和某堆牧草的坐标完全重合。
输入格式
? 第一行:两个整数 N 和 K, 1 ≤ N ≤ 100000, 1 ≤ K ≤ 2000000
? 第二行到第 N + 1 行:第 i + 1 行有三个整数: Ai, Xi 和 Yi, 1 ≤ Ai ≤ 10000, 0 ≤ Xi,Yi ≤
1000000
输出格式
? 单个整数:表示距离和最佳位置不超过 K 的牧草数量之和
样例输入
4 3
7 8 6
3 0 0
4 6 0
1 4 2
样例输出
8
解释
选择 (3, 0) 为家,位置在 (0, 0), (6, 0) 和
(4, 2) 的牧草距离家都不超过 K
来源
The Lazy Cow, 2014 Mar
【分析】
曼哈顿距离的话,那个范围,应该是一个边长和坐标轴呈45度角的正方形。
这样就有点难搞,难统计。
我们需要把图形“旋转一下”
旋转的目标是让正方形的边长平行于坐标轴。、
那么,观察一下可以得到,可以把nx=x-y ny=x+y 这样就旋转过来了(其实改变了正方形的大小的,但没有关系,只要能判断出曼哈顿距离是不是<=k就好)
然后就很简单了,用线段树维护y纵坐标,然后x横坐标线性扫描。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 2000010 10 11 struct hp 12 { 13 int a,ax,ay; 14 }tt[Maxn]; 15 16 struct node 17 { 18 int l,r,lc,rc,ans; 19 int lazy; 20 }t[2*Maxn];int len; 21 22 int mymin(int x,int y) {return x<y?x:y;} 23 int mymax(int x,int y) {return x>y?x:y;} 24 25 bool cmp(hp x,hp y) {return x.ax<y.ax;} 26 int n,k; 27 28 int build(int l,int r) 29 { 30 int x=++len; 31 t[x].l=l;t[x].r=r; 32 t[x].ans=0;t[x].lazy=0; 33 if(l!=r) 34 { 35 int mid=(l+r)>>1; 36 t[x].lc=build(l,mid); 37 t[x].rc=build(mid+1,r); 38 } 39 else t[x].lc=t[x].rc=0; 40 return x; 41 } 42 43 void init() 44 { 45 scanf("%d%d",&n,&k); 46 int mx=0; 47 for(int i=1;i<=n;i++) 48 { 49 scanf("%d%d%d",&tt[i].a,&tt[i].ax,&tt[i].ay); 50 int xx=tt[i].ax; 51 tt[i].ax=tt[i].ax-tt[i].ay;tt[i].ay=xx+tt[i].ay+1; 52 mx=mymax(mx,tt[i].ay); 53 } 54 sort(tt+1,tt+1+n,cmp); 55 k=k*2; 56 build(1,mx); 57 } 58 59 void upd(int x) 60 { 61 if(t[x].lazy==0) return; 62 t[x].ans+=t[x].lazy; 63 int lc=t[x].lc,rc=t[x].rc; 64 if(t[x].l!=t[x].r) 65 { 66 t[lc].lazy+=t[x].lazy; 67 t[rc].lazy+=t[x].lazy; 68 } 69 t[x].lazy=0; 70 } 71 72 void change(int x,int l,int r,int y) 73 { 74 if(t[x].l==l&&t[x].r==r) 75 { 76 t[x].lazy+=y; 77 return; 78 } 79 upd(x); 80 int mid=(t[x].l+t[x].r)>>1; 81 if(r<=mid) change(t[x].lc,l,r,y); 82 else if(l>mid) change(t[x].rc,l,r,y); 83 else 84 { 85 change(t[x].lc,l,mid,y); 86 change(t[x].rc,mid+1,r,y); 87 } 88 upd(t[x].lc);upd(t[x].rc); 89 t[x].ans=mymax(t[t[x].lc].ans,t[t[x].rc].ans); 90 } 91 92 void ffind() 93 { 94 int j=0,ans=0; 95 for(int i=1;i<=n;i++) 96 { 97 while(j<n&&tt[j+1].ax-tt[i].ax<=k) 98 { 99 int nx=mymax(1,tt[j+1].ay-k); 100 change(1,nx,tt[j+1].ay,tt[j+1].a); 101 j++; 102 } 103 upd(1); 104 ans=mymax(ans,t[1].ans); 105 change(1,mymax(1,tt[i].ay-k),tt[i].ay,-tt[i].a); 106 } 107 printf("%d\n",ans); 108 } 109 110 int main() 111 { 112 init(); 113 ffind(); 114 return 0; 115 }
2016-10-31 11:25:57
【BZOJ 3476】 线段树===