首先如果办公室和家在同一侧,直接将距离加到答案中即可。
如果办公室和家不在同一侧
对于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;
}