500题留念:
对于不过桥的人在最后加进答里就行了。
一个人过桥一定是先从a到桥再从桥到b。
对于K=1的情况,设桥的位置为x,答案就是
∑|a[i]−x|+∑|b[i]−x|
。因此选在所有a和b的中间最优。
对于K!=1的情况,考虑如果当前点选的桥坐标为x,那么对于这个点,答案是
−b−a+2x
(a,b都在桥左),
|b−a|
(a,b跨桥),
a+b−2x
(a,b都在桥右)。
因此可以发现当桥的位置为
a+b2
时最优,离
a+b2
越远越不优。
因此每个点选离
a+b2
最近的桥。将所有点按
a+b2
排序。那么一个前缀的点去第一个桥,剩下的后缀的点去第二个桥。
然后在前缀和后缀内用K=1时的方法。
用两个平衡树维护前缀和后缀。支持插入,删除,查询第K大,求子树点到定点的距离(维护区间的size和区间所有点到inf和-inf的距离和)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define which(x) (ch[fa[x]][1]==x)
const int inf=1e9+10,N=110000;
int K,n,cnt;
ll ans,fin;
char s1[11],s2[11];
struct node
{
int x,y;
node(){}
node(int x,int y):x(x),y(y){}
friend bool operator < (const node &r1,const node &r2)
{return r1.x+r1.y<r2.x+r2.y;}
}a[N];
struct Splay
{
int cnt,root;
int size[N<<1],ch[N<<1][2],fa[N<<1],val[N<<1],num[N<<1];
ll sl[N<<1],sr[N<<1];
void pushup(int x)
{
sl[x]=sl[ch[x][0]]+sl[ch[x][1]]+(ll)num[x]*(inf+val[x]);
sr[x]=sr[ch[x][0]]+sr[ch[x][1]]+(ll)num[x]*(inf-val[x]);
size[x]=size[ch[x][0]]+size[ch[x][1]]+num[x];
}
Splay()
{
cnt=2;root=1;
ch[1][0]=2;fa[2]=1;
val[2]=-inf;val[1]=inf;
num[1]=num[2]=1;
pushup(2);pushup(1);
}
void rotate(int x)
{
int y=fa[x],k=which(x);
ch[y][k]=ch[x][k^1];
ch[x][k^1]=y;
ch[fa[y]][which(y)]=x;
fa[x]=fa[y];fa[y]=x;
fa[ch[y][k]]=y;
pushup(y);pushup(x);
}
void splay(int x,int tar)
{
while(fa[x]!=tar)
{
int y=fa[x];
if(fa[y]==tar)rotate(x);
else
{
if(which(x)^which(y))
rotate(x);
else rotate(y);
rotate(x);
}
}
if(!tar)root=x;
}
int find_val(int x,int v)
{
if(val[x]==v)return x;
if(v<val[x])return find_val(ch[x][0],v);
return find_val(ch[x][1],v);
}
int find_kth(int x,int K)
{
if(K>size[ch[x][0]]&&size[ch[x][0]]+num[x]>=K)
return x;
if(size[ch[x][0]]>=K)
return find_kth(ch[x][0],K);
return find_kth(ch[x][1],K-size[ch[x][0]]-num[x]);
}
void up(int x)
{
if(!x)return;
pushup(x);up(fa[x]);
}
void insert(int v)
{
int x=root;
while(1)
{
if(val[x]==v)
{num[x]++;up(x);break;}
if(v<val[x])
{
if(!ch[x][0])
{
ch[x][0]=++cnt;fa[cnt]=x;
num[cnt]=size[cnt]=1;val[cnt]=v;
up(cnt);break;
}
x=ch[x][0];
}
else
{
if(!ch[x][1])
{
ch[x][1]=++cnt;fa[cnt]=x;
num[cnt]=size[cnt]=1;val[cnt]=v;
up(cnt);break;
}
x=ch[x][1];
}
}
splay(x,0);
}
void del(int v)
{
int x=find_val(root,v);
num[x]--;splay(x,0);
}
ll query()
{
int x=find_kth(root,size[root]/2);
splay(x,0);
return sr[ch[x][0]]-(ll)(inf-val[x])*size[ch[x][0]]
+sl[ch[x][1]]-(ll)(val[x]+inf)*size[ch[x][1]]-
(val[x]+inf)-(inf-val[x]);
}
}tr1,tr2;
int main()
{
//freopen("tt.in","r",stdin);
scanf("%d%d",&K,&n);
for(int i=1,x1,x2;i<=n;i++)
{
scanf("%s%d%s%d",&s1,&x1,&s2,&x2);
if(s1[0]==s2[0])ans+=abs(x1-x2);
else a[++cnt]=node(x1,x2),ans++;
}
sort(a+1,a+1+cnt);
fin=1ll<<60;
for(int i=1;i<=cnt;i++)
{
tr2.insert(a[i].x);
tr2.insert(a[i].y);
}
fin=min(fin,tr1.query()+tr2.query());
if(K==1)return printf("%lld\n",fin+ans),0;
for(int i=1;i<=cnt;i++)
{
tr2.del(a[i].x);
tr2.del(a[i].y);
tr1.insert(a[i].x);
tr1.insert(a[i].y);
fin=min(fin,tr1.query()+tr2.query());
}
printf("%lld\n",ans+fin);
return 0;
}