【bzoj3476-懒惰的奶牛】线段树

题解:

感觉这题和别人的做法不一样。。。呵呵呵。。。调了一百年。。

设家坐标为(a,b),对于每个点(x,y),可以转化为|a-x|+|b-y|<=k

对于每个点,它的影响范围是一个菱形(也就是一个正方形啦。。),也就是一个图上有若干个正方形。

然后我就把这个坐标轴选择了45度。

好难画不画了,正交分解一下就可以了。

然后题目就转化成正方形各种交里的最大值。

正方形有x和y两个元素,但是很明显我们只能维护一个。。

所以我以x轴建立线段树,对于每个正方形按照y从小到大排序。

维护一个指针j,表示当前前j个正方形已经和现在在处理的第i个正方形没有交集。每次都要先把j更新(看看它是否能后移)。

然后我们在当前正方形的两端a[i].x~a[i].y这一段+a[i].d

每个点维护当前的和d以及该区间的最大值mx。每次做完之后,用t[1].mx更新答案。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<ctime>
  6 #include<queue>
  7 #include<algorithm>
  8 using namespace std;
  9
 10 const int N=1001000,INF=(int)1e9;
 11 int n,K,L,tl,ans;
 12 struct trnode{
 13     int l,r,lc,rc,d,mx,lazy;
 14 }t[4*N];
 15 struct node{
 16     int x,y,d;
 17 }a[N];
 18
 19 bool cmp(node x,node y){return x.y<y.y;}
 20 int maxx(int x,int y){return x>y ? x:y;}
 21 int minn(int x,int y){return x<y ? x:y;}
 22
 23 int read()
 24 {
 25     int x=0,f=1; char ch=getchar();
 26     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();}
 27     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();}
 28     return x*f;
 29 }
 30
 31 int bt(int l,int r)
 32 {
 33     int x=++tl;
 34     t[x].l=l;t[x].r=r;
 35     t[x].lc=t[x].rc=0;
 36     t[x].mx=0;t[x].d=0;
 37     t[x].lazy=0;
 38     if(l<r)
 39     {
 40         int mid=(l+r)/2;
 41         t[x].lc=bt(l,mid);
 42         t[x].rc=bt(mid+1,r);
 43     }
 44     return x;
 45 }
 46
 47 void pd(int x)
 48 {
 49     if(t[x].lazy==0) return ;
 50     int d=t[x].lazy,lc=t[x].lc,rc=t[x].rc;
 51     t[x].lazy=0;
 52     t[x].d+=d;
 53     t[x].mx+=d;
 54     if(lc) t[lc].lazy+=d;
 55     if(rc) t[rc].lazy+=d;
 56 }
 57
 58 void change(int x,int l,int r,int d)
 59 {
 60     pd(x);
 61     if(t[x].l==l && t[x].r==r)
 62     {
 63         t[x].lazy+=d;
 64         pd(x);
 65         return ;
 66     }
 67     int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;
 68     if(r<=mid) change(lc,l,r,d);
 69     else if(l>mid) change(rc,l,r,d);
 70     else
 71     {
 72         change(lc,l,mid,d);
 73         change(rc,mid+1,r,d);
 74     }
 75     pd(x);pd(lc);pd(rc);
 76     t[x].mx=maxx(t[lc].mx,t[rc].mx);
 77 }
 78
 79 int main()
 80 {
 81     // freopen("a.in","r",stdin);
 82     // freopen("me.out","w",stdout);
 83     freopen("lazy.in","r",stdin);
 84     freopen("lazy.out","w",stdout);
 85     n=read();K=read();
 86     // scanf("%d%d",&n,&K);
 87     int x,y,tx,ty,nx=INF,ny=INF,mx=0;tl=0;L=2*K;
 88     for(int i=1;i<=n;i++)
 89     {
 90         a[i].d=read();x=read();y=read();
 91         // scanf("%d%d%d",&a[i].d,&x,&y);
 92         tx=x,ty=y+K;
 93         a[i].x=tx-ty;
 94         a[i].y=tx+ty;
 95
 96         nx=minn(nx,a[i].x);
 97         ny=minn(ny,a[i].y);
 98     }
 99     for(int i=1;i<=n;i++)
100     {
101         a[i].x-=nx-1;
102         a[i].y-=ny-1;
103         mx=maxx(mx,a[i].x);
104     }
105     mx+=10;ans=0;
106     sort(a+1,a+1+n,cmp);
107     bt(1,mx);
108     int j=1;
109     change(1,a[1].x,minn(mx,a[1].x+L),a[1].d);
110     ans=maxx(ans,t[1].mx);
111     for(int i=2;i<=n;i++)
112     {
113         while(j<i && a[i].y-L>a[j].y)
114         {
115             change(1,a[j].x,minn(mx,a[j].x+L),-a[j].d);
116             ans=maxx(ans,t[1].mx);
117             j++;
118         }
119         change(1,a[i].x,minn(mx,a[i].x+L),a[i].d);
120         ans=maxx(ans,t[1].mx);
121     }
122     printf("%d\n",ans);
123     return 0;
124 }
时间: 2024-10-21 03:35:33

【bzoj3476-懒惰的奶牛】线段树的相关文章

nyoj 116 士兵杀敌(四)(线段树区间更新和单点查询)

题目123 题目信息 运行结果 本题排行 讨论区 士兵杀敌(四) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个人身上,这样,有时候,计算他们中的哪一个人到底有多少军功就是一个比较困难的事情,军师小工的任务就是在南将军询问他某个人的军功的时候,快速的报出此人的军功,请你编写一个程序来

hdu 1698 Just a Hook(线段树,成段更新,懒惰标记)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18384    Accepted Submission(s): 9217 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible thing

【HDU 4614】Vases and Flowers(线段树区间更新懒惰标记)

题目0到n-1的花瓶,操作1在下标a开始插b朵花,输出始末下标.操作2清空[a,b]的花瓶,求清除的花的数量.线段树懒惰标记来更新区间.操作1,先查询0到a-1有num个空瓶子,然后用线段树的性质,或者二分找出第num+1个空瓶子的下标,和第num+b个空瓶子的下标.再区间更新为满.操作2,也相当于区间更新为空. #include<cstdio> #include<cstring> #include<algorithm> #define N 50001 using na

HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1 还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻 要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了 rev操作不改变set操作,在

【POJ】3468 A Simple Problem with Integers ——线段树 成段更新 懒惰标记

A Simple Problem with Integers Time Limit:5000MS   Memory Limit:131072K Case Time Limit:2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each

线段树懒惰点标记更新 hduHDU - 1698 Just a Hook

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1698 题意:自行读题 解题思想:线段树原更新一次只能更新一个叶子节点,并更新此叶子结点以上所有相关的点,当一个区间做相同更新时,叶子节点以上的相关节点不断更新,时间复杂度增加.为节省时间,为每个点添加懒惰标记.自定义节点范围(l,r为求子节点区间和),懒惰点标记(lazy储存变化值),节点和(value节点区间和).具体实现过程:当更新一个区间时,标记该区间的父亲节点为懒惰区间(祖宗节点的值不用标记

【BZOJ 3476】 线段树===

59  懒惰的奶牛贝西所在的牧场,散落着 N 堆牧草,其中第 i 堆牧草在 ( Xi,Yi ) 的位置,数量有 Ai 个单位.贝西从家移动到某一堆牧草的时候,只能沿坐标轴朝正北.正东.正西.正南这四个方向移动,所以计算贝西和牧草间的距离时,应采用"曼哈顿距离"-- (x,y ) 和 (x ′,y ′) 之间的距离为|x ? x ′ | + |y ? y ′ |.例如贝西的家在 (0.5, 0.3),有一堆牧草在 (3, 2),那么它们之间的距离就是 4.2.贝西懒得走动,她想请你为它寻

hihoCode 1078 : 线段树的区间修改

#1078 : 线段树的区间修改 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho: 假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi.小Hi的每次操作分为两种可能,第一种是修改价格——小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP.第二种操作是询问——小Hi给出一段

POJ-3468 A Simple Problem with Integers(线段树)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 94899   Accepted: 29568 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of