传送门
感觉是一道和计算几何没有什么关系的计算几何
题解:
容易注意到其实题目分为完全不相干的两个部分。
首先是算 c c c的出现次数,然后是计算最多和最少能够出现多少个 a a a。
交换的最多次数其实就是交点个数,因为交点个数就是逆序对个数。
或者可以感性理解一下,如果在每个相交的地方都交换方向,显然全程所有飞机的相对顺序都不会改变,最后结果就一定符合要求。
根据一点群论知识知道把最终排列结果看作是一个置换,最少操作次数是 n − 循 环 个 数 n-循环个数 n−循环个数。
现在考虑怎么计算 c c c的次数。
首先求交点可以直接在把结尾位置归并排序的时候一起处理。复杂度 O ( n log n + 交 点 个 数 ) O(n\log n+交点个数) O(nlogn+交点个数)
然后所有点和正方形逆时针旋转 π 4 \frac{\pi}{4} 4π并且放大两倍,其实就是曼哈顿距离转切比雪夫距离。
然后扫描线加入和删除线段, 查询当前有没有线段覆盖这个点。
所有线段按照左端点排序,维护前缀的右端点最大值即可。
选择你喜欢的数据结构随便写一写即可。
其实也可以KD-tree,但是5e5个点看上去不是很友好,结果跑出来比扫描线还快
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
using pii=std::pair<int,int>;
#define fi first
#define se second
cs int N=1e5+7;
struct Pnt{
double x,y;
Pnt(){}
Pnt(double _x,double _y):x(_x),y(_y){}
inline Pnt rot(){return Pnt(x-y,x+y);}
};
int A,B,C;ll ans1,ans2;
int xst,xed,n,m,tot;
Pnt p[N*5];//交点
pii c[N];int r[N];//观测点
namespace Scan_Line{
struct seg{int l,r;};
struct atom{int p;seg t;};
atom ins[N],del[N];int tl,ct;
int ps[N];
namespace SGT{
cs int N=1<<18|7;
std::multiset<int> s[N>>1];int mx[N],M,n;
inline void init(){
std::sort(ps+1,ps+tl+1);
n=std::unique(ps+1,ps+tl+1)-ps-1;
for(M=1;M<=n+1;M<<=1);
memset(mx,-0x3f,sizeof mx);
}
inline void update(int p){
mx[p+M]=s[p].empty()?-0x3f3f3f3f:*s[p].rbegin();
for(p+=M;p>>=1,p;)mx[p]=std::max(mx[p<<1],mx[p<<1|1]);
}
inline void ins(cs seg &t){
int p=t.l,v=t.r;p=std::lower_bound(ps+1,ps+n+1,p)-ps;
s[p].insert(v);update(p);
}
inline void del(cs seg &t){
int p=t.l,v=t.r;p=std::lower_bound(ps+1,ps+n+1,p)-ps;
s[p].erase(s[p].find(v));update(p);
}
inline int query(int l,int r){
int ans=-0x3f3f3f3f;if(l>r)return ans;
for(l+=M-1,r+=M+1;l^r^1;l>>=1,r>>=1){
if(~l&1)ans=std::max(ans,mx[l^1]);
if(r&1) ans=std::max(ans,mx[r^1]);
}
return ans;
}
inline bool check(cs Pnt &p){
int r=std::upper_bound(ps+1,ps+n+1,p.y)-ps-1;
return query(1,r)>=p.y;
}
}
inline void work(){
for(int re i=1;i<=tot;++i)p[i]=p[i].rot();
std::sort(p+1,p+tot+1,[](cs Pnt &a,cs Pnt &b){return a.x<b.x;});
for(int re i=1;i<=m;++i){
++tl;ps[tl]=c[i].se-r[i];
ins[tl]=(atom){c[i].fi-r[i],(seg){c[i].se-r[i],c[i].se+r[i]}};
del[tl]=(atom){c[i].fi+r[i],(seg){c[i].se-r[i],c[i].se+r[i]}};
}SGT::init();
std::sort(ins+1,ins+tl+1,[](cs atom &a,cs atom &b){return a.p<b.p;});
std::sort(del+1,del+tl+1,[](cs atom &a,cs atom &b){return a.p<b.p;});
for(int re i=1,a=1,b=1;i<=tot;++i){
while(a<=tl&&ins[a].p<=p[i].x)SGT::ins(ins[a++].t);
while(b<=tl&&del[b].p<p[i].x)SGT::del(del[b++].t);
if(SGT::check(p[i]))++ct;
}
ans1=(ll)C*ct+(ll)A*tot,ans2=(ll)C*ct+(ll)B*tot;
}
}
inline void work(int y1,int y2,int y3,int y4){
double t=y2+y3-y1-y4;
double x=(y3-y1)/t*(xed-xst)+xst;
double y=(y3-y1)/t*(y2-y1)+y1;
p[++tot]=Pnt(x,y);
}
pii a[N],b[N];
inline void get_intersections(int l,int r){
if(l==r)return ;int mid=l+r>>1;
get_intersections(l,mid);
get_intersections(mid+1,r);
for(int re i=l,j=mid+1;i<=mid;++i){
while(a[j].se<a[i].se&&j<=r)++j;
for(int re k=mid+1;k<j;++k)work(a[i].fi,a[i].se,a[k].fi,a[k].se);
}
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)b[k++]=a[(a[i].se<a[j].se)?i++:j++];
while(i<=mid)b[k++]=a[i++];
while(j<=r)b[k++]=a[j++];
for(int re i=l;i<=r;++i)a[i]=b[i];
}
int num[N],vis[N];
int ps[N],to[N];
signed main(){
#ifdef zxyoi
freopen("fly.in","r",stdin);
#endif
n=gi(),A=gi(),B=gi(),C=gi(),xst=gi(),xed=gi();
for(int re i=1;i<=n;++i)a[i].fi=gi();
for(int re i=1;i<=n;++i)a[i].se=num[i]=gi();
std::sort(num+1,num+n+1);
for(int re i=1;i<=n;++i){
ps[i]=std::lower_bound(num+1,num+n+1,a[i].se)-num;
to[ps[i]]=i;
}
get_intersections(1,n);m=gi();
for(int re i=1;i<=m;++i){
int x=gi(),y=gi();r[i]=gi();
c[i]=pii(x-y,x+y);
}
Scan_Line::work();int ct=n;
for(int re i=1;i<=n;++i)if(!vis[i]){--ct;while(!vis[i]){vis[i]=true;i=to[i];}}
ans2+=(ll)ct*(A-B);
if(ans1>ans2)std::swap(ans1,ans2);
cout<<ans1<<" "<<ans2<<"\n";
return 0;
}