poj2464扫描线好题,回头再做

it2022-05-05  109

扫描线+区间更新

题解

/* st[i],ol[i]表示y坐标大于y[i]和小于y[i]的点 两颗线段树建立在y轴上,区间[l,r]ol线选在[l,r]时st的分数 每次查询完成后再更新一次 遍历每条st线上的ol线,这是单点查询 */ #include<iostream> #include<cstring> #include<cstdio> #include<map> #include<vector> #include<algorithm> using namespace std; #define N 200005 #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define MID(a,b) (a+((b-a)>>1)) struct Point{ int x,y; void get(){scanf("%d%d",&x,&y);} bool operator<(const Point & b)const { return x<b.x; } } p[N]; struct node{//线段树结点 int lft,rht; int flag[2]; int mid(){return MID(lft,rht);} void init(int a,int b){flag[0]=a;flag[1]=b;} }; int n,m,mi; vector<int> mx; map<int,int> H; int y[N],st[N],ol[N];//离散化数轴,大于等于y[i]的点数,小于等于y[i]的点 struct Segtree{ node tree[N*4]; void down(int ind){ for(int i=0;i<2;i++){ tree[LL(ind)].flag[i]+=tree[ind].flag[i]; tree[RR(ind)].flag[i]+=tree[ind].flag[i]; tree[ind].flag[i]=0; } } void build(int lft,int rht,int ind){ tree[ind].lft=lft;tree[ind].rht=rht; tree[ind].init(0,0); if(lft==rht) tree[ind].init(st[lft],ol[lft]); else { int mid=tree[ind].mid(); build(lft,mid,LL(ind)); build(mid+1,rht,RR(ind)); } } void update(int st,int ed,int ind,int type,int valu){ int lft=tree[ind].lft,rht=tree[ind].rht; if(st<=lft && ed>=rht) tree[ind].flag[type]+=valu; else { down(ind); int mid=tree[ind].mid(); if(st<=mid) update(st,ed,LL(ind),type,valu); if(ed>mid) update(st,ed,LL(ind),type,valu); } } void query(int pos,int ind,int &mi,int &mx){ if(tree[ind].lft==tree[ind].rht){ mi=tree[ind].flag[0]; mx=tree[ind].flag[1]; } else { down(ind); int mid=tree[ind].mid(); if(pos<=mid) return query(pos,LL(ind),mi,mx); if(pos>mid) return query(pos,RR(ind),mi,mx); } } }seg; int main(){ while(scanf("%d",&n),n){ H.clear();mx.clear();mi=m=0; int id1=0,id2=0; for(int i=0;i<n;i++){ p[i].get(); y[i]=p[i].y; } sort(y,y+n); sort(p,p+n);//把点按从左往右顺序排好 H[y[0]]=0; for(int i=0;i<n;i++)//遍历一次纵坐标 if(y[m]!=y[i]){ st[m]=n-i;//高于y[i]的点数 y[++m]=y[i]; ol[m]=i;//低于y[i]的点数 H[y[m]]=m; } st[m]=0; seg.build(0,m,1); while(id1<n){ id2=id1; while(p[id1].x==p[id2].x){//这一步删掉被st线穿过的点 //不是最低的点 if(p[id2].y!=y[0]) //ol线低于p[id2].y情况的st分数就少了一份 seg.update(H[y[0]],H[p[id2].y]-1,1,0,-1); //不是最高的点 if(p[id2].y!=y[m]) //ol线高于p[id2].y的时候 seg.update(H[p[id2].y]+1,H[y[m]],1,1,-1); if(++id2>=n) break; } int mii=n,mxx=0; for(int i=id1;i<id2;i++){//依次在st线上的点建立ol线并进行查询,找到使st得分最低的那个点 int tmp1,tmp2; seg.query(H[p[i].y],1,mii,mxx); mii=min(mii,tmp1); mxx=max(mxx,tmp2); } if(mii==mi) mx.push_back(mxx);//找到了ol的新解 else if(mii>mi){//找到了st的更优解 mi=mii; mx.clear();mx.push_back(mxx); } //再更新一次,把这条线上删掉的反向加回去:因为扫描线往后扫描这条线上原来应该属于ol的现在属于st,原来属于st的现在应该属于ol for(int i=id1;i<id2;i++){ if(p[i].y!=y[0]) seg.update(H[y[0]],H[p[i].y]-1,1,1,1); if(p[i].y!=y[m]) seg.update(H[p[i].y]+1,H[y[m]],1,0,1); } id1=id2; } sort(mx.begin(),mx.end()); mx.erase(unique(mx.begin(),mx.end()),mx.end()); printf("Stan: %d; Ollie:",mi); for(int i=0;i<mx.size();i++) printf(" %d",mx[i]); printf(";\n"); } return 0; }

 

转载于:https://www.cnblogs.com/zsben991126/p/9958441.html

相关资源:各显卡算力对照表!

最新回复(0)