Description
太长了自己看。。。
Solution
强行题套题,真·GDOI模拟
首先可以发现A和B操作都不会影响交点的位置,那么C的贡献就是固定的了。这个可以先求出交点然后转换坐标系二维数点,离线拆分扫描线+树状数组就行了。因为有可能是实数所以离散不太好写
考虑什么时候能交换就交换。注意到一次相交意味着二者在最后会交换顺序,因此每个交点都做一次A恰好能满足初始相对顺序,且在A>B的时候是最优的。而当A<B的时候,这样算出来的一定会是较小的答案。
当A<B的时候,我们把每个航线向自己的目的位置连边,那么全部满足正确相对位置的交换次数恰好就是n-连通块数量。也就是我们至少要做这么多次A,剩余的都可以拿来做B。
然后就做完了。细节比较多
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define lb(x) (x&-x)
typedef long double ld;
const int N=2000005;
const ld eps=1e-9;
struct pos {
ld x,y;
} p[N],jiao[N];
struct Q {
ld x;
int y1,y2,xs;
} q[N];
int r[N],id[N],s[N],n,cb,cj,cq;
ld b[N];
bool vis[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add(int x,int v) {
for (;x<=cb+5;x+=lb(x)) s[x]+=v;
}
int get(int x) {
int res=0;
for (;x;x-=lb(x)) res+=s[x];
return res;
}
pos inte(pos a,pos b,pos c,pos d) {
ld a1=b.y-a.y,b1=a.x-b.x;
ld c1=a1*a.x+b1*a.y;
ld a2=d.y-c.y,b2=c.x-d.x;
ld c2=a2*c.x+b2*c.y;
ld cross=a1*b2-a2*b1;
if (cross==0) return {-1,-1};
else return {(b2*c1-b1*c2)/cross,(a1*c2-a2*c1)/cross};
}
bool cmp1(int x,int y) {
return p[x+n].y<p[y+n].y;
}
bool cmp2(Q x,Q y) {
if (fabs(x.x-y.x)>eps) return x.x<y.x;
if (x.xs!=y.xs) return x.xs>y.xs;
return false;
}
int main(void) {
freopen("data.in","r",stdin);
n=read(); int A=read(),B=read(),C=read();
int sx=read(),ex=read();
rep(i,1,n) p[i].x=sx,p[i].y=read();
rep(i,1,n) p[i+n].x=ex,p[i+n].y=read();
rep(i,1,n) id[i]=i;
std:: sort(id+1,id+n+1,cmp1);
rep(i,1,n) r[id[i]]=i;
int cnt=n;
rep(i,1,n) if (!vis[i]) {
cnt--; int x=r[i];
while (x!=i) vis[x]=1,x=r[x];
}
rep(i,1,n) id[i]=i;
rep(i,1,n) rep(j,i,n*2) if (i==r[j]) {
int aj=id[j];
drp(k,j-1,i) {
pos res=inte(p[id[k]],p[id[k]+n],p[aj],p[aj+n]);
jiao[++cj]=(pos) {res.x+res.y,res.x-res.y};
std::swap(r[k],r[k+1]);
id[k+1]=id[k];
} break;
}
int m=read();
rep(i,1,m) {
int tx=read(),ty=read(),c=read();
int x=tx+ty,y=tx-ty;
q[++cq]=(Q) {(ld)x-c,y-c,y+c,1}; b[cq]=y-c;
q[++cq]=(Q) {(ld)x+c,y-c,y+c,-1}; b[cq]=y+c;
}
cb=cq;
rep(i,1,cj) b[++cb]=jiao[i].y;
std:: sort(b+1,b+cb+1);
int tmp=cb; cb=1;
rep(i,2,tmp) if (fabs(b[i]-b[i-1])>eps) b[++cb]=b[i];
rep(i,1,cq) {
q[i].y1=std:: lower_bound(b+1,b+cb+1,q[i].y1)-b;
q[i].y2=std:: lower_bound(b+1,b+cb+1,q[i].y2)-b;
}
rep(i,1,cj) {
int y=std:: lower_bound(b+1,b+cb+1,jiao[i].y)-b;
q[++cq]=(Q) {jiao[i].x,y};
}
std:: sort(q+1,q+cq+1,cmp2);
int wjp=0;
rep(i,1,cq) {
if (q[i].xs) {
add(q[i].y1,q[i].xs);
add(q[i].y2+1,-q[i].xs);
} else wjp+=(get(q[i].y1)!=0);
}
int mxs=A*cj+wjp*C;
int mns=A*cnt+B*(cj-cnt)+wjp*C;
if (mxs<mns) std:: swap(mxs,mns);
printf("%d %d\n", mns,mxs);
return 0;
}