首先如果办公室和家在同一侧,直接将距离加到答案中即可。
如果办公室和家不在同一侧
对于k=1,显然只需要将桥建在所有位置的中位数即可。
对于k=2,可以发现每个人都会选择距离家和办公室中点较近的桥行走。那么我们就可以按照家和办公室中点将每个人排序,枚举分割点,将分割点前后的人分别处理。在权值线段树上二分求中位数
#include<cstdio> #include<cstdlib> #include<algorithm> using namespace std; typedef long long ll; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++; } inline void read(int &x) { char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; } inline void read(char &x) { for (x=nc();x!='A' && x!='B';x=nc()); } const int N=200005; int n,K,tot; int icnt,sx[N]; ll ans,all_add; inline int Bin(int x){ return lower_bound(sx+1,sx+icnt+1,x)-sx; } inline int dist(int x,int y){ return abs(sx[x]-sx[y]); } struct abcd{ int l,r; abcd(int l=0,int r=0):l(l),r(r) { } bool operator < (const abcd &B) const { return l+r<B.l+B.r; } }a[N]; struct SEGTREE{ int M,TH; int T[N*4]; ll H[N*4]; inline void Build(int n){ for (M=1,TH=0;M<n+2;TH++,M<<=1); } inline void add(int s,int r,ll x){ T[s+=M]+=r; H[s]+=r*x; while (s>>=1) T[s]+=r,H[s]+=r*x; } inline ll sum(int s,int t){ if (s>t) return 0; ll ret=0; for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1) { if (~s&1) ret+=H[s^1]; if ( t&1) ret+=H[t^1]; } return ret; } inline ll cnt(int s,int t){ if (s>t) return 0; ll ret=0; for (s+=M-1,t+=M+1;s^t^1;s>>=1,t>>=1) { if (~s&1) ret+=T[s^1]; if ( t&1) ret+=T[t^1]; } return ret; } inline int Mid(){ int K=T[1]/2+1,i; for (i=1;i<M;) if (T[i<<1]<K) K-=T[i<<1],i=i<<1|1; else i=i<<1; return i-M; } }SEG1,SEG2; inline ll Solve(int m){ ll ret=0,mid; if (m) { mid=SEG1.Mid(); ret+=m; ret+=SEG1.cnt(1,mid-1)*sx[mid]-SEG1.sum(1,mid-1); ret+=SEG1.sum(mid+1,icnt)-SEG1.cnt(mid+1,icnt)*sx[mid]; } if (n-m) { mid=SEG2.Mid(); ret+=tot-m; ret+=SEG2.cnt(1,mid-1)*sx[mid]-SEG2.sum(1,mid-1); ret+=SEG2.sum(mid+1,icnt)-SEG2.cnt(mid+1,icnt)*sx[mid]; } return ret; } int main() { char w,z; int x,y; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(K); read(n); if (K==1) { for (int i=1;i<=n;i++) { read(w); read(x); read(z); read(y); if (w==z) ans+=abs(x-y); else sx[++icnt]=x,sx[++icnt]=y; } sort(sx+1,sx+icnt+1); x=sx[icnt/2+1]; ans+=icnt/2; for (int i=1;i<=icnt;i++) ans+=abs(sx[i]-x); printf("%lld\n",ans); return 0; } for (int i=1;i<=n;i++) { read(w); read(x); read(z); read(y); if (x>y) swap(x,y); if (w==z) all_add+=abs(x-y); else a[++tot]=abcd(x,y); } sort(a+1,a+tot+1); for (int i=1;i<=tot;i++) sx[++icnt]=a[i].l,sx[++icnt]=a[i].r; sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1; SEG1.Build(icnt); SEG2.Build(icnt); for (int i=1;i<=tot;i++) a[i].l=Bin(a[i].l),a[i].r=Bin(a[i].r); ans=1LL<<60; for (int i=1;i<=tot;i++) SEG2.add(a[i].l,1,sx[a[i].l]),SEG2.add(a[i].r,1,sx[a[i].r]); ans=min(ans,Solve(0)); for (int i=1;i<=tot;i++) { SEG1.add(a[i].l,1,sx[a[i].l]); SEG1.add(a[i].r,1,sx[a[i].r]); SEG2.add(a[i].l,-1,sx[a[i].l]); SEG2.add(a[i].r,-1,sx[a[i].r]); ans=min(ans,Solve(i)); } printf("%lld\n",ans+all_add); return 0; }