前言
卡了很长时间的一个题。
一开始 k=1 的关键性质把握就跑偏了,后面基本在硬做…
关键就是一直把每个人当成一条线段作为整体在看,使问题很复杂…
最后用 three-pointers
磕磕绊绊搞出来了。
但是根本不用!
解析
这题关键就在于:k=1k=1k=1 怎么做?
我直接暴力枚举桥的位置,因此 k=2k=2k=2 就没了。
这个贡献可以拆分为 家-桥-公司。
所以问题转化成:给出 2n 个点,求一个点使所有点到其距离和最小。
显然是中位数。
接下来考虑 k=2k=2k=2 怎么做?
我们尝试维护两座桥对应的集合,一开始A为空、B为全集,不断把B集合的元素扔到A里,动态维护代价和取min即可。
手玩一下,不难发现按照左右端点坐标和为关键字排序扔即可。
然后就是动态维护中位数了。维护两个堆即可轻松实现动态添加元素维护中位数,B集合的删除也可以反着做化删为加。
然而懒得写了,还是贴的 three pointers
。
代码
#include<bits/stdc++.h>
#include<string>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}const int N=2e5+100;
const int mod=998244353;
const int inf=1e9;bool mem1;inline ll ksm(ll x,ll k){ll res=1;while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}int n,m;int q[N],cnt;
int x[N],y[N];
char c1[N],c2[N];ll bas,ans=1e18;
struct seg{int l,r,id;
}p[N];
bool operator < (const seg &x,const seg &y){return q[x.l]+q[x.r]<q[y.l]+q[y.r];
}
int num;
vector<seg>l[N],r[N];
int num0l[N],num0r[N],num1l[N],num1r[N];
bool tag[N];
void work1(){ll sl(0),sr(0),nl(0),nr(0);for(int i=1;i<=cnt;i++){nr+=num0l[i];for(seg o:l[i]){sr+=q[o.l];}}for(int i=1;i<=cnt;i++){nr-=num0l[i-1];for(seg o:l[i-1]){sr-=q[o.l];}nl+=num0r[i];for(seg o:r[i]){sl+=q[o.r];} ans=min(ans,sr-nr*q[i]+nl*q[i]-sl);//printf("i=%d nl=%lld sl=%lld nr=%lld sr=%lld ans=%lld\n",q[i],nl,sl,nr,sr,ans);}printf("%lld\n",ans*2+bas);
}
void work2(){ll sxl(0),nxl(0),sxr(0),nxr(0),syl(0),nyl(0),syr(0),nyr(0),x=1,y=1;sort(p+1,p+1+num);for(int i=1;i<=num;i++){if(p[i].l>1){syr+=q[p[i].l];nyr++;} }while(y<cnt&&nyl+num0r[y]<nyr){for(seg o:r[y]){syl+=q[o.r];nyl++;}++y;for(seg o:l[y]){syr-=q[o.l];nyr--;}}for(int i=1;i<=num;i++){tag[p[i].id]=1;if(p[i].r<y){syl-=q[p[i].r];nyl--;}if(p[i].l>y){syr-=q[p[i].l];nyr--;}if(p[i].l>x){sxr+=q[p[i].l];nxr++;}if(p[i].r<x){sxl+=q[p[i].r];nxr--;}num0r[p[i].r]--;num1r[p[i].r]++;num0l[p[i].l]--;num1l[p[i].l]++;//printf(" (%lld %lld) (%lld %lld)\n",nyl,syl,nyr,syr);while(y<cnt&&nyl+num0r[y]<nyr){for(seg o:r[y]){if(tag[o.id]) continue;syl+=q[o.r];nyl++;}++y;for(seg o:l[y]){if(tag[o.id]) continue;syr-=q[o.l];nyr--;}}while(x<cnt&&nxl+num1r[x]<nxr){ for(seg o:r[x]){if(!tag[o.id]) continue;sxl+=q[o.r];nxl++;}++x;for(seg o:l[x]){if(!tag[o.id]) continue;sxr-=q[o.l];nxr--;}//printf("")}ans=min(ans,syr-nyr*q[y]+nyl*q[y]-syl+sxr-nxr*q[x]+nxl*q[x]-sxl);//printf("(%d %d) x=%d y=%d %lld %lld\n",q[p[i].l],q[p[i].r],q[x],q[y],syr-nyr*q[y]+nyl*q[y]-syl,sxr-nxr*q[x]+nxl*q[x]-sxl);//printf(" (%lld %lld) (%lld %lld) ans=%lld\n",nxl,sxl,nxr,sxr,ans); //puts("");}debug("ans=%lld\n",ans);printf("%lld\n",ans*2+bas);
}bool mem2;
signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endif//debug("mem=%.4lf\n",abs(&mem2-&mem1)/1024./1024);m=read();n=read();for(int i=1;i<=n;i++){scanf(" %c%d %c%d",&c1[i],&x[i],&c2[i],&y[i]);if(x[i]>y[i]) swap(x[i],y[i]);q[++cnt]=x[i];q[++cnt]=y[i];}sort(q+1,q+1+cnt);cnt=unique(q+1,q+1+cnt)-q-1; for(int i=1;i<=n;i++){x[i]=lower_bound(q+1,q+1+cnt,x[i])-q;y[i]=lower_bound(q+1,q+1+cnt,y[i])-q;bas+=q[y[i]]-q[x[i]];if(c1[i]!=c2[i]){++bas;num0l[x[i]]++;num0r[y[i]]++;++num;l[x[i]].emplace_back((seg){x[i],y[i],num});r[y[i]].emplace_back((seg){x[i],y[i],num});p[num]=(seg){x[i],y[i],num};}}if(m==1) work1();else work2();return 0;
}