1. 程式人生 > >[GX/GZOI2019]特技飛行(掃描線+置換)

[GX/GZOI2019]特技飛行(掃描線+置換)

正方 clas iterator b- class cli 至少 lose hide

感覺是6題中最難的一題,其實這題是一個二合一:

第一問:給定平面上若幹點和k個關鍵點,關鍵點覆蓋一個45°傾斜的正方形範圍r,求有多少點被至少一個關鍵點覆蓋。這個可以曼哈頓轉切比雪夫距離,然後再掃描線求解,復雜度O(nlogn)

第二問:求最少和最多有多少次擦肩而過。顯然每個交點都可以做對向交換,這是最少擦肩而過的次數。最多的次數,假設全部擦肩而過得到排列p,對向交換實際上是交換兩元素位置,用最小交換次數還原排列即可。

技術分享圖片
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>pii;
const int N=5e5+7; int n,m,a,b,c,x0,x1,ans1,ans2,tot,cnt,ans,C[N<<1],y[N][2],f[N],vis[N]; double d[N<<1]; set<pii>S; struct node{double x,y;int v,p;}p[N<<1]; bool operator<(node a,node b){return a.x<b.x;} node calc(int i,int j) { int y1=y[j][0]-y[i][0],y2=y[i][1
]-y[j][1]; double k=1.0*y1/(y1+y2),xl=1.0*x0+k*(x1-x0),yl=1.0*y[i][0]+k*(y[i][1]-y[i][0]); d[++cnt]=xl-yl; return(node){xl+yl,xl-yl,0,0}; } bool cmp(node a,node b){return fabs(a.x-b.x)<1e-10?a.y<b.y:a.x<b.x;} void add(int x,int v){while(x<=cnt)C[x]+=v,x+=x&-x;} int query(int x){int
ret=0;while(x)ret+=C[x],x-=x&-x;return ret;} bool cmp1(int a,int b){return y[a][1]<y[b][1];} int main() { scanf("%d%d%d%d%d%d",&n,&a,&b,&c,&x0,&x1); for(int i=1;i<=n;i++)scanf("%d",&y[i][0]); for(int i=1;i<=n;i++)scanf("%d",&y[i][1]); for(int i=1;i<=n;i++) { pii u=make_pair(y[i][1],i); set<pii>::iterator it=S.lower_bound(u); while(it!=S.end())p[++tot]=calc(it->second,i),it++; S.insert(u); } int sum=tot;scanf("%d",&m); for(int i=1,x,y,z;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); d[++cnt]=x-y+z,d[++cnt]=x-y-z; p[++tot]=(node){x+y+z,x-y+z,1,0}; p[++tot]=(node){x+y+z,x-y-z,-1,0}; p[++tot]=(node){x+y-z,x-y+z,-1,0}; p[++tot]=(node){x+y-z,x-y-z,1,0}; } sort(p+1,p+tot+1); sort(d+1,d+cnt+1); cnt=unique(d+1,d+cnt+1)-d-1; for(int i=1;i<=tot;i++)p[i].p=upper_bound(d+1,d+cnt+1,p[i].y-1e-10)-d; sort(p+1,p+tot+1,cmp); for(int i=1;i<=tot;i++)if(p[i].v)add(p[i].p,p[i].v);else ans+=query(p[i].p)>0; ans1=ans*c+sum*a; for(int i=1;i<=n;i++)f[i]=i; sort(f+1,f+n+1,cmp1); int num=n; for(int i=1;i<=n;i++) if(!vis[i]) { num--; for(int j=i;!vis[j];j=f[j])vis[j]=1; } ans2=ans1+(b-a)*(sum-num); if(ans1>ans2)swap(ans1,ans2); printf("%d %d",ans1,ans2); }
View Code

[GX/GZOI2019]特技飛行(掃描線+置換)