【题目】
LOJ
有 n n n架飞机从起点飞到终点,对地速度相同。每当两架飞机飞到同一点,可以选择交换飞行路线(对向交换)或继续原路线(擦肩而过),分别有 a a a和 b b b的得分。另外有 k k k个观测点 ( p i , q i ) (p_i,q_i) (pi,qi),可以观测到曼哈顿距离它不超过 r i r_i ri的区域。若两架飞机飞到同一点时被至少一个观测点观测到,则会额外获得 c c c的得分。
现在要求到达终点时飞机相对顺序不变,求最大可能得分和最小可能得分。
n , k ≤ 1 0 5 n,k\leq 10^5 n,k≤105,交点数 ≤ 5 × 1 0 5 \leq 5\times 10^5 ≤5×105
【解题思路】
首先 c c c是可以单独拿出来计算的,这个我们后面再说。
对于 a , b a,b a,b,我们可以观察到若一直对向交换显然是合法的,那这一定是一个最值,另一个最值要求我们最小化对向交换的次数,即最大化擦肩而过的次数。
考虑若全部擦肩而过,则我们实际上可以得到若干个置换,而每个置换一定是独立的。那么对于每个大小为 x x x的置换来说,实际上其交换的下界就是 x − 1 x-1 x−1,这个可以考虑每个交点相当于创造一个逆序对吧,就是要将逆序对全部交换回来。于是对向交换的最小次数就是 n − n- n−置换个数。
于是 a , b a,b a,b的贡献看起来很难,反而可以 O ( n ) O(n) O(n)算了。
对于 c c c,实际上就是数有多少个交点被包含在矩形中。首先求交点的话实际上就是每个逆序对,我们随便用一个 set \text{set} set之类的维护然后按顺序插入数字就可以了。然后曼哈顿距离还要拆绝对值来算,我们转成切比雪夫距离,然后就可以直接扫描线做了。
这部分的复杂度大概是 O ( k log n ) O(k\log n) O(klogn)的,但常数极大,至少我们被KD树做法吊打。
【参考代码】
#include
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
using namespace std;
typedef pair<int,int> pii;
typedef double db;//use long double will be slower
const int N=1e5+10,M=N*5;
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
namespace Data_Structure
{
int cnt;
struct line
{
int x,yl,yr,op;
line(int _x=0,int _l=0,int _r=0,int _o=0):x(_x),yl(_l),yr(_r),op(_o){}
bool operator <(const line&rhs)const{return x==rhs.x?op>rhs.op:x<rhs.x;}
}li[M<<1];
struct Segment
{
#define ls (x<<1)
#define rs (x<<1|1)
int tag[M*6];
void update(int x,int l,int r,int L,int R,int v)
{
if(L<=l && r<=R) {tag[x]+=v;return;}
int mid=(l+r)>>1;
if(L<=mid) update(ls,l,mid,L,R,v);
if(R>mid) update(rs,mid+1,r,L,R,v);
}
int query(int x,int l,int r,int p)
{
if(l==r) return tag[x];
int mid=(l+r)>>1;
if(p<=mid) return tag[x]+query(ls,l,mid,p);
else return tag[x]+query(rs,mid+1,r,p);
}
#undef ls
#undef rs
}tr;
}
using namespace Data_Structure;
namespace DreamLolita
{
int n,A,B,C,S,T,K,cro,ans1,ans2,MI,MX;
int R[N],be[N],ed[N],vis[N];
db b[N],k[N];
set<pii>st;
struct point
{
db x,y;
point(db _x=0,db _y=0):x(_x),y(_y){}
}p[M],vs[N];
void addcross(int i,int j)
{
//printf("getcross:%d %d\n",i,j);
db x=(b[j]-b[i])/(k[i]-k[j]),y=k[i]*x+b[i];
p[++cro]=point(x+y,x-y);
}
void getcross()
{
for(int i=1;i<=n;++i) k[i]=(1.0*(ed[i]-be[i]))/(1.0*(T-S)),b[i]=1.0*be[i]-k[i]*S;
for(int i=1;i<=n;++i)
{
for(auto it=st.lower_bound(mkp(ed[i],i));it!=st.end();++it) addcross(i,(*it).se);
st.insert(mkp(ed[i],i));
}
//printf("cross:%d\n",cro);
//for(int i=1;i<=cro;++i) printf("%Lf %Lf\n",p[i].x,p[i].y);
}
pair<int,int>a[N];
void dfs(int x){vis[x]=1;if(!vis[a[x].se])dfs(a[x].se);}
void calcAB()
{
for(int i=1;i<=n;++i) a[i]=mkp(ed[i],i);
sort(a+1,a+n+1);
for(int i=1;i<=n;++i) if(!vis[i]) ++ans1,dfs(i);
MI=A*cro;MX=(n-ans1)*A+(cro-(n-ans1))*B;
if(MI>MX) swap(MI,MX);
//printf("MI:%d MX:%d\n",MI,MX);
}
int cntx,cnty;
db px[M<<1],py[M<<1];
void calcC()
{
for(int i=1;i<=K;++i) px[++cntx]=vs[i].x-R[i],px[++cntx]=vs[i].x+R[i],py[++cnty]=vs[i].y-R[i],py[++cnty]=vs[i].y+R[i];
for(int i=1;i<=cro;++i) px[++cntx]=p[i].x,py[++cnty]=p[i].y;
sort(px+1,px+cntx+1);cntx=unique(px+1,px+cntx+1)-px-1;
sort(py+1,py+cnty+1);cnty=unique(py+1,py+cnty+1)-py-1;
for(int i=1;i<=K;++i)
{
int xl=lower_bound(px+1,px+cntx+1,vs[i].x-R[i])-px,xr=lower_bound(px+1,px+cntx+1,vs[i].x+R[i])-px;
int yl=lower_bound(py+1,py+cnty+1,vs[i].y-R[i])-py,yr=lower_bound(py+1,py+cnty+1,vs[i].y+R[i])-py;
li[++cnt]=line(xl,yl,yr,1);li[++cnt]=line(xr,yl,yr,-1);
}
for(int i=1;i<=cro;++i)
{
int x=lower_bound(px+1,px+cntx+1,p[i].x)-px,y=lower_bound(py+1,py+cnty+1,p[i].y)-py;
li[++cnt]=line(x,y,0,0);
}
sort(li+1,li+cnt+1);
//puts("lines:");
//for(int i=1;i<=cnt;++i) printf("%d %d %d %d\n",li[i].x,li[i].yl,li[i].yr,li[i].op);
for(int i=1,j,r;i<=cnt;i=j+1)
{
j=i-1;r=j+1;
while(li[j+1].x==li[i].x && li[j+1].op==1) ++j;
for(int l=r;l<=j;++l) tr.update(1,1,cnty,li[l].yl,li[l].yr,1);
r=j+1;
while(li[j+1].x==li[i].x && li[j+1].op==0) ++j;
for(int l=r;l<=j;++l) ans2+=(tr.query(1,1,cnty,li[l].yl)>0?1:0);
r=j+1;
while(li[j+1].x==li[i].x && li[j+1].op==-1) ++j;
for(int l=r;l<=j;++l) tr.update(1,1,cnty,li[l].yl,li[l].yr,-1);
}
MI+=ans2*C;MX+=ans2*C;
}
void solution()
{
n=read();A=read();B=read();C=read();S=read();T=read();
for(int i=1;i<=n;++i) be[i]=read();
for(int i=1;i<=n;++i) ed[i]=read();
K=read();
for(int i=1;i<=K;++i)
{
int x=read(),y=read();R[i]=read();
vs[i].x=x+y;vs[i].y=x-y;
}
getcross();calcAB();calcC();
printf("%d %d\n",MI,MX);
}
}
int main()
{
#ifdef Durant_Lee
freopen("LOJ3085.in","r",stdin);
freopen("LOJ3085.out","w",stdout);
#endif
DreamLolita::solution();
return 0;
}