zoukankan      html  css  js  c++  java
  • 【BZOJ4071】【APIO2015】巴邻旁之桥

    题意:

    Description

    一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B。

    每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1000000000。相邻的每对建筑相隔 1 个单位距离,河的宽度也是 1 个单位长度。区域 A 中的 i 号建筑物恰好与区域 B 中的 i 号建筑物隔河相对。
    城市中有 N 个居民。第 i 个居民的房子在区域 Pi 的 Si 号建筑上,同时他的办公室坐落在 Qi 区域的 Ti 号建筑上。一个居民的房子和办公室可能分布在河的两岸,这样他就必须要搭乘船只才能从家中去往办公室,这种情况让很多人都觉得不方便。为了使居民们可以开车去工作,政府决定建造不超过 K 座横跨河流的大桥。
    由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。当政府建造最多 K 座桥之后,设 Di 表示第 i 个居民此时开车从家里到办公室的最短距离。请帮助政府建造桥梁,使得 D1+D2+⋯+DN 最小。
    所有数据都保证:Pi 和 Qi 为字符 “A” 和 “B” 中的一个, 0≤Si,Ti≤1000000000 ,同一栋建筑内可能有超过 1 间房子或办公室(或二者的组合,即房子或办公室的数量同时大于等于 1)。
    子任务 1 (8 分)K=1,1≤N≤1000
    子任务 2 (14 分)K=1,1≤N≤100000
    子任务 3 (9 分)K=2,1≤N≤100
    子任务 4 (32 分)K=2,1≤N≤1000
    子任务 5 (37 分)K=2,1≤N≤100000

    Input

    输入的第一行包含两个正整数 K 和 N,分别表示桥的上限数量和居民的数量。

    接下来 N 行,每一行包含四个参数:Pi,Si,Qi 和 Ti,表示第 i 个居民的房子在区域 Pi 的 Si 号建筑上,且他的办公室位于 Qi 区域的 Ti 号建筑上。

    Output

    输出仅为一行,包含一个整数,表示 D1+D2+⋯+DN 的最小值。

    题解:

    首先,这题可以三分!可以三分!可以三分!

    认(sui)真(bian)分(cai)析(xiang)一下可以发现,$K=1$时总花费时间随桥从左到右变化的函数是个单峰函数,$K=2$时是两个单峰函数通过某种变换之后叠加在一起,最后还是个单峰函数(然而我并不会证)

    因此可以先三分第一个桥,再三分第二个桥,三分套三分的时间复杂度是$O(nlog^210^9)$的,手算大概有2.5亿,实测可以过掉前四个subtask,获得63分的好成绩(雾)

    正解是权值线段树动态维护中位数。。。

    $K=1$就不说了,大家都会。。。

    $K=2$时有一个结论:每个人必定会走更接近$frac{A_i+B_i}{2}$的那座桥,易得这样必定更优;

    所以可以先按照$A_i+B_i$排序,左半边的人就会走左桥,右半边就走右桥;

    然后就没了。。。左右各写一个数据结构,支持快速插入/删除,快速查询中位数和区间和,可以直接splay,也可以用权值线段树黑科技来做(新技能get√)

    ps:所谓的黑科技就是,左右儿子哪个size大就走哪个,最后的叶节点就是中位数。。。

    代码:

    三分:(请木公爷来卡常啊啊啊)

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<queue>
     7 #define inf 10000000000000000
     8 #define eps 1e-9
     9 using namespace std;
    10 typedef long long ll;
    11 struct pp{
    12     ll s1,s2,t1,t2;
    13 }p[100001];
    14 ll n,K,ans=inf,l,r,maxn=0;
    15 char sd1[2],sd2[2];
    16 ll gaogao(ll k,ll kk){
    17     ll ret=0;
    18     for(ll i=1;i<=n;i++){
    19         if(p[i].s1==p[i].s2)ret+=abs(p[i].t1-p[i].t2);
    20         else ret+=min(abs(p[i].t1-k)+abs(p[i].t2-k)+1,abs(p[i].t1-kk)+abs(p[i].t2-kk)+1);
    21     }
    22     return ret;
    23 }
    24 ll gao(ll k){
    25     if(K==1){
    26         ll ret=0;
    27         for(ll i=1;i<=n;i++){
    28             if(p[i].s1==p[i].s2)ret+=abs(p[i].t1-p[i].t2);
    29             else ret+=abs(p[i].t1-k)+abs(p[i].t2-k)+1;
    30         }
    31         return ret;
    32     }
    33     ll ret=inf,l=0,r=maxn;
    34     while(l+3<=r){
    35         ll mid=l+(r-l)/3,mmid=r-(r-l)/3;
    36         if(gaogao(k,mid)<=gaogao(k,mmid))r=mmid;
    37         else l=mid;
    38     }
    39     for(ll i=l;i<=r;i++){
    40         ret=min(ret,gaogao(k,i));
    41     }
    42     return ret;
    43 }
    44 int main(){
    45     scanf("%lld%lld",&K,&n);
    46     for(ll i=1;i<=n;i++){
    47         scanf("%s%lld%s%lld",sd1,&p[i].t1,sd2,&p[i].t2);
    48         p[i].s1=sd1[0]-'A';
    49         p[i].s2=sd2[0]-'A';
    50         maxn=max(maxn,max(p[i].t1,p[i].t2));
    51     }
    52     l=0,r=maxn;
    53     while(l+3<=r){
    54         ll mid=l+(r-l)/3,mmid=r-(r-l)/3;
    55         if(gao(mid)<=gao(mmid))r=mmid;
    56         else l=mid;
    57     }
    58     for(ll i=l;i<=r;i++){
    59         ans=min(ans,gao(i));
    60     }
    61     printf("%lld",ans);
    62     return 0;
    63 }

    权值线段树:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #include<queue>
      7 #define inf 1000000000000000
      8 #define eps 1e-9
      9 using namespace std;
     10 typedef long long ll;
     11 struct pp{
     12     ll t1,t2;
     13     friend bool operator <(pp a,pp b){
     14         return a.t1+a.t2<b.t1+b.t2;
     15     }
     16 }p[200001];
     17 struct node{
     18     ll v,siz;
     19 }t[1000001][2];
     20 ll n,k,t1,t2,x1,x2,x3,x4,m1,m2,nw1=0,nw2=0,els=0,sum=0,cnt=0,ans=inf,num[200001];
     21 char s1[2],s2[2];
     22 void updata(ll l,ll r,ll u,ll p,ll x,ll ch){
     23     t[u][ch].siz+=x;
     24     t[u][ch].v+=x*num[p];
     25     if(l==r)return;
     26     ll mid=(l+r)/2;
     27     if(p<=mid)updata(l,mid,u*2,p,x,ch);
     28     else updata(mid+1,r,u*2+1,p,x,ch);
     29 }
     30 ll get(ll l,ll r,ll u,ll x,ll ch){
     31     if(l==r)return l;
     32     ll mid=(l+r)/2;
     33     if(x<=t[u*2][ch].siz)return get(l,mid,u*2,x,ch);
     34     else return get(mid+1,r,u*2+1,x-t[u*2][ch].siz,ch);
     35 }
     36 ll query(ll l,ll r,ll u,ll L,ll R,ll ch,ll xx){
     37     if(L<=l&&r<=R){
     38         return xx?t[u][ch].v:t[u][ch].siz;
     39     }
     40     ll mid=(l+r)/2,ret=0;
     41     if(L<=mid)ret+=query(l,mid,u*2,L,R,ch,xx);
     42     if(mid<R)ret+=query(mid+1,r,u*2+1,L,R,ch,xx);
     43     return ret;
     44 }
     45 int main(){
     46     scanf("%lld%lld",&k,&n);
     47     if(k==1){
     48         for(ll i=1;i<=n;i++){
     49             scanf("%s%lld%s%lld",s1,&t1,s2,&t2);
     50             if(s1[0]==s2[0])els+=abs(t1-t2);
     51             else{
     52                 num[++cnt]=t1;
     53                 num[++cnt]=t2;
     54             }
     55         }
     56         ans=els+cnt/2;
     57         sort(num+1,num+cnt+1);
     58         for(ll i=1;i<=cnt;i++){
     59             ans+=abs(num[i]-num[cnt/2]);
     60         }
     61         printf("%lld",ans);
     62     }else{
     63         for(ll i=1;i<=n;i++){
     64             scanf("%s%lld%s%lld",s1,&t1,s2,&t2);
     65             if(s1[0]==s2[0])els+=abs(t1-t2);
     66             else{
     67                 num[++cnt]=t1;
     68                 num[++cnt]=t2;
     69                 p[++sum].t1=t1;
     70                 p[sum].t2=t2;
     71             }
     72         }
     73         if(!sum)return printf("%lld
    ",els),0;
     74         els+=sum;
     75         sort(num+1,num+cnt+1);
     76         cnt=unique(num+1,num+cnt+1)-num-1;
     77         sort(p+1,p+sum+1);
     78         for(ll i=1;i<=sum;i++){
     79             nw1+=p[i].t1+p[i].t2;
     80             p[i].t1=lower_bound(num+1,num+cnt+1,p[i].t1)-num;
     81             p[i].t2=lower_bound(num+1,num+cnt+1,p[i].t2)-num;
     82             updata(1,cnt,1,p[i].t1,1,1);
     83             updata(1,cnt,1,p[i].t2,1,1);
     84         }
     85         for(ll i=1;i<=sum;i++){
     86             nw2+=num[p[i].t1]+num[p[i].t2];
     87             nw1-=num[p[i].t1]+num[p[i].t2];
     88             updata(1,cnt,1,p[i].t1,1,0);
     89             updata(1,cnt,1,p[i].t1,-1,1);
     90             updata(1,cnt,1,p[i].t2,1,0);
     91             updata(1,cnt,1,p[i].t2,-1,1);
     92             m1=get(1,cnt,1,i,0);
     93             m2=get(1,cnt,1,sum-i,1);
     94             x1=query(1,cnt,1,1,m1,0,1);
     95             x2=query(1,cnt,1,1,m2,1,1);
     96             x3=query(1,cnt,1,1,m1,0,0);
     97             x4=query(1,cnt,1,1,m2,1,0);
     98             ans=min(ans,x3*num[m1]-x1+(nw2-x1)-(i*2-x3)*num[m1]+x4*num[m2]-x2+(nw1-x2)-((sum-i)*2-x4)*num[m2]);
     99         }
    100         printf("%lld",ans+els);
    101     }
    102     return 0;
    103 }
  • 相关阅读:
    2014年终总结
    杭电2014——青年歌手大奖赛_评委会打分
    nyoj---t448(寻找最大数)
    nyoj_t218(Dinner)
    将string转换成char*
    nyoj71--独木舟上的旅行
    基于贪心算法的几类区间覆盖问题
    会场安排问题—NYOJ14
    南阳理工ACM——106背包问题
    南阳理工91——阶乘之和
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9834464.html
Copyright © 2011-2022 走看看