[线段树 中位数] BZOJ 4071 [Apio2015]巴邻旁之桥

来源:互联网 发布:ios屏幕检测软件 编辑:程序博客网 时间:2024/06/05 22:30

首先如果办公室和家在同一侧,直接将距离加到答案中即可。

如果办公室和家不在同一侧

对于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;elsei=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;}


0 0
原创粉丝点击