UESTC 1525 Fruit Ninja(扫描线)

来源:互联网 发布:永恒之塔数据库4.7 编辑:程序博客网 时间:2024/04/29 20:45

题意:有T组测试数据,每组数据的N,H,W表示有N个炸弹或水果,H和W表示用来“切”水果的板砖的长宽,要求W必须平行于X轴,H必须平行于Y轴。问一板砖下去,最多能拍到多少个水果(要求不能拍到炸弹),在拍到最多水果的前提下,问板砖有多少种拍水果的方案(即如果板砖的四条边上都要水果“牺牲”,那么方案数计一,否则板砖就可移动,那么方案数就是so many!)

        下面的N行,每行给出炸弹或水果的坐标,L X Y,如果L是'G'表示水果,如果是'B'表示炸弹,X和Y是坐标。1<=N<=50000, 1<=X,Y,H,W<=25000。

        扫描线,方法类似于star in my window。不同的是我们把y的坐标乘以2,这样线段就是(x,y*2,(y+h)*2),(x+w,y*2,(y+h)*2)。这样,如果是下标为奇数的点到达最大值,我们知道方案数一定是so many,这是y轴方向的限制——即与y平行的两条边上都有水果,怎么处理x方向上的限制呢?我们把在依次遍历每条边的时候,一次只处理x坐标相同的几条边(在排序的时候,我们优先入边(加水果的边)再出边(减水果的边),因为边框上的水果是计入的),先处理入边,这时候,可能更新最大值,后处理出边时,如果这时最大值不变,那么说明方案数也有so many。

        最后线段树的节点里记录拍到的水果的最大值和对应的方案树。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define LL(x) (x<<1)#define RR(x) (x<<1|1)#define MID(a,b) (a+((b-a)>>1))#define INF (1LL<<30)const int N=100000;typedef long long LL;struct Segtree{struct Seg{int lft,rht;LL mx,cov,delay;int mid(){ return MID(lft,rht); }void init(){ mx=delay=0; cov=INF; }void fun(LL tmp) { mx+=tmp; delay+=tmp; }}tree[N*4];void PushDown(int ind){if(tree[ind].delay){tree[LL(ind)].fun(tree[ind].delay);tree[RR(ind)].fun(tree[ind].delay);tree[ind].delay=0;}}void PushUp(int ind){tree[ind].mx=max(tree[LL(ind)].mx,tree[RR(ind)].mx);tree[ind].cov=0;if(tree[ind].mx==tree[LL(ind)].mx)tree[ind].cov+=tree[LL(ind)].cov;if(tree[ind].mx==tree[RR(ind)].mx)tree[ind].cov+=tree[RR(ind)].cov;}void build(int lft,int rht,int ind){tree[ind].lft=lft;tree[ind].rht=rht;tree[ind].init();if(lft==rht){if( (lft&1) ==0 ) tree[ind].cov=1;}else{int mid=tree[ind].mid();build(lft,mid,LL(ind));build(mid+1,rht,RR(ind));}}void updata(int st,int ed,int ind,int valu){int lft=tree[ind].lft,rht=tree[ind].rht;if(st<=lft&&rht<=ed) tree[ind].fun(valu);else{PushDown(ind);int mid=tree[ind].mid();if(st<=mid) updata(st,ed,LL(ind),valu);if(ed> mid) updata(st,ed,RR(ind),valu);PushUp(ind);}}}seg;struct Line{int x,y1,y2,st,v;Line(){}Line(int x,int y1,int y2,int st,int v) :x(x),y1(y1),y2(y2),st(st),v(v) {}bool operator<(const Line &b)const{return x<b.x||(x==b.x&&st>b.st);}}line[N*4];int main(){int t;scanf("%d",&t);while(t--){int n,h,w,nl=0,mi=INF,mx=-INF;scanf("%d%d%d",&n,&h,&w);for(int i=0;i<n;i++){char op[5]; int x,y,y1,y2;scanf("%s%d%d",op,&x,&y);y1=y*2;y2=(y+h)*2;mi=min(mi,y1); mx=max(mx,y2);if(op[0]=='G'){line[nl++]=Line(x,y1,y2,1,1);line[nl++]=Line(x+w,y1,y2,-1,-1);}else{line[nl++]=Line(x,y1,y2,1,-INF);line[nl++]=Line(x+w,y1,y2,-1,INF);}}sort(line,line+nl);seg.build(mi,mx,1);LL ans=0,cnt=0;for(int i=0;i<nl;){int last=line[i].x;while(i<nl&&line[i].x==last&&line[i].st==1){seg.updata(line[i].y1,line[i].y2,1,line[i].v);i++;}if(ans==seg.tree[1].mx) cnt+=seg.tree[1].cov;else if(ans<seg.tree[1].mx){ans=seg.tree[1].mx;cnt=seg.tree[1].cov;}while(i<nl&&line[i].x==last&&line[i].st==-1){seg.updata(line[i].y1,line[i].y2,1,line[i].v);i++;}if(ans<=seg.tree[1].mx){ans=seg.tree[1].mx;cnt=INF;}}if(cnt>=INF) puts("so many!");else printf("%lld\n",cnt);printf("%lld\n\n",ans);}return 0;}


原创粉丝点击