Link:

BZOJ 4071传送门

Solution:

首先算出能提前算的贡献

$K=1$:肯定选中间的点,小学数学

$K=2$:对于每对$(x,y)$一定选离$(x+y)/2$近的桥

也就是说将$(x,y)$按$(x+y)/2$的值排序后一定恰有一个分割点使得两边选择不同的桥!

考虑如何如何快速枚举所有分割点时的答案:

需要支持插入、删除、求中位数及两边的和,明显选择$Splay$来维护(求和更容易些)

这样先将所有数对加进一个$Splay$,再不断将其中的数移向另一棵$Splay$即可

注意:可能以前的$Splay$板子容易出不少锅啊……

首先$Update$时最好对$z$进行判断,然后$Splay$最后也要$Pushup$否则会在树高低时不更新$size$

Code:

#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef double db;
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=2e5+;//注意范围
const ll INF=<<; struct Splay
{
ll sum[MAXN];
int rt,tot,f[MAXN],sz[MAXN],cnt[MAXN],ch[MAXN][],val[MAXN];
void update(int x)
{
sz[x]=sz[ch[x][]]+sz[ch[x][]]+cnt[x];
sum[x]=sum[ch[x][]]+sum[ch[x][]]+1ll*val[x]*cnt[x];
}
void rotate(int x)
{
int y=f[x],z=f[y],k=(ch[y][]==x);
//最好对z特判一下防止对ch[0]操作
if(z) ch[z][ch[z][]==y]=x;f[x]=z;
ch[y][k]=ch[x][k^];f[ch[x][k^]]=y;
ch[x][k^]=y;f[y]=x;
update(y);update(x);
}
void splay(int x,int up)
{
while(f[x]!=up)
{
int y=f[x],z=f[y];
if(z!=up) (ch[y][]==x)^(ch[z][]==y)?rotate(x):rotate(y);
rotate(x);
}
if(!up) rt=x;
//!!!!!!!!
update(x);//可能f[x]=up,但也要update
}
void insert(int x)
{
int k=rt,anc=;
while(k&&val[k]!=x)
anc=k,k=ch[k][x>val[k]];
if(k) cnt[k]++;
else
{
k=++tot;
if(anc) ch[anc][x>val[anc]]=k;
val[k]=x;cnt[k]=;f[k]=anc;sz[k]=;
}
splay(k,);
}
void find(int x)
{
int k=rt;
while(x!=val[k]&&ch[k][x>val[k]])
k=ch[k][x>val[k]];
splay(k,);
}
int kth(int x)
{
int k=rt;
//对当前为空的情况特判
if(sz[k]<x||!x) return ;
while(true)
{
if(x>sz[ch[k][]]+cnt[k])
x-=sz[ch[k][]]+cnt[k],k=ch[k][];
else if(x<=sz[ch[k][]]) k=ch[k][];
else return k;
}
}
//不用加边界的删除法
void del(int x)
{
find(x);
if(val[rt]!=x) return;
if(cnt[rt]>) cnt[rt]--;
else if(!ch[rt][]||!ch[rt][])
{
int k=ch[rt][]+ch[rt][];
f[k]=;rt=k;
}
else
{
int k=ch[rt][];
while(ch[k][]) k=ch[k][];
splay(k,rt);
ch[k][]=ch[rt][];
f[ch[k][]]=k;
rt=k;f[k]=;
}
//由于后面没有splay了要update
update(rt);
}
ll query()
{
int k=kth(sz[rt]/);
if(!k) return ;splay(k,);
ll ret1=1ll*val[k]*sz[ch[k][]]-sum[ch[k][]];
ll ret2=sum[ch[k][]]-1ll*val[k]*sz[ch[k][]];
return ret1+ret2;
}
}s1,s2; char a[],b[];
ll res=1ll<<,pre;
int n,x,y,k,tot;P dat[MAXN]; bool cmp(P a,P b){return a.X+a.Y<b.X+b.Y;}; int main()
{
scanf("%d%d",&k,&n);
for(int i=;i<=n;i++)
{
scanf("%s%d%s%d",a,&x,b,&y);
if(a[]==b[]) pre+=abs(x-y);
else dat[++tot]=P(x,y),pre++;
}
//注意特判!!!
if(!tot) return printf("%lld",pre),;
sort(dat+,dat+tot+,cmp); for(int i=;i<=tot;i++)
s1.insert(dat[i].X),s1.insert(dat[i].Y);
if(k==) return printf("%lld",s1.query()+pre),; for(int i=;i<=tot;i++)
{
s1.del(dat[i].X);s1.del(dat[i].Y);
s2.insert(dat[i].X);s2.insert(dat[i].Y);
res=min(res,s1.query()+s2.query());
}
printf("%lld",res+pre);
return ;
}

[BZOJ 4071] 巴邻旁之桥的更多相关文章

  1. 【BZOJ4071】[Apio2015]巴邻旁之桥 Treap

    [BZOJ4071][Apio2015]巴邻旁之桥 Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 ...

  2. 4071: [Apio2015]巴邻旁之桥

    Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...

  3. BZOJ4071 & 洛谷3644 & UOJ112:[APIO2015]巴邻旁之桥——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4071 https://www.luogu.org/problemnew/show/P3644 ht ...

  4. [bzoj4071] [Apio2015]巴邻旁之桥

    Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...

  5. 【BZOJ4071】【APIO2015】巴邻旁之桥

    题意: Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1 ...

  6. bzoj 4071: [Apio2015]巴邻旁之桥【splay】

    用权值线段树会容易一些并快一些,但是想复健一下splay所以打了splay 然后果然不会打了. 解题思路: 首先把家和办公室在同一侧的提出来直接加进答案里: 对于k=1,直接选所有办公室和家的中位数即 ...

  7. [APIO2015]巴邻旁之桥

    Bzoj权限题 luogu题面 先去掉同边的 首先k==1,即求一个点j 使\(\sum_{i\in A} |D_i - D_j| + \sum_{i\in B} |D_i - D_j|\)最小 因为 ...

  8. 【LOJ】#2888. 「APIO2015」巴邻旁之桥 Palembang Bridges

    题解 发现我们选择一座桥会选择力\(\frac{s + t}{2}\)较近的一座桥 然后我们只需要按照\(s + t\)排序,然后枚举断点,左边取所有s和t的中位数,右边同理 动态求中位数用平衡树维护 ...

  9. 「APIO2015」巴邻旁之桥 Palembang Bridges

    贪心 先转化一下题意 首先如果一个人的家和办公室在河同一侧那么建桥的时候不用去考虑它,最终把答案加上即可 在河两侧的家和办公室互换不影响答案,那么可以把这个抽象到一个区间$[l,r]$,距离就是$|l ...

随机推荐

  1. 【CodeForces】915 G. Coprime Arrays 莫比乌斯反演

    [题目]G. Coprime Arrays [题意]当含n个数字的数组的总gcd=1时认为这个数组互质.给定n和k,求所有sum(i),i=1~k,其中sum(i)为n个数字的数组,每个数字均< ...

  2. ue4 TimeRemaining(ratio)找不到的问题

    最近看ue4的Blueprint 3rd Person Game的教学视频,其中第十集https://docs.unrealengine.com/latest/INT/Videos/PLZlv_N0_ ...

  3. 读书笔记 ~ Python黑帽子 黑客与渗透测试编程之道

    Python黑帽子  黑客与渗透测试编程之道   <<< 持续更新中>>> 第一章: 设置python 环境 1.python软件包管理工具安装 root@star ...

  4. go语言基本介绍

    Golang发展历史 1. 诞生历史a. 诞生与2006年1月2号下午15点4分5秒b. 2009发布并正式开源c. 2012年第一个正式版本Go 1.0发布d. 截至到2017年8月24号Go 1. ...

  5. 宋牧春: Linux设备树文件结构与解析深度分析(1) 【转】

    转自:https://mp.weixin.qq.com/s/OX-aXd5MYlE_YoZ3p32qWA 作者简介 宋牧春,linux内核爱好者,喜欢阅读各种开源代码(uboot.linux.ucos ...

  6. 64_n3

    nodejs-yamlish-0.0.5-9.fc26.noarch.rpm 11-Feb-2017 16:48 11966 nodejs-yargs-3.2.1-6.fc26.noarch.rpm ...

  7. caffe Python API 之图片预处理

    # 设定图片的shape格式为网络data层格式 transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape}) ...

  8. Python 根据地址获取经纬度及求距离

    方法一: 使用Geopy包 : https://github.com/geopy/geopy   (仅能精确到城镇,具体街道无结果返回) from geopy.geocoders import Nom ...

  9. 登陆记录utmp wtmp

    /var/log/wtmp文件的作用     /var/log/wtmp也是一个二进制文件,记录每个用户的登录次数和持续时间等信息.   查看方法:   可以用last命令输出当中内容: debian ...

  10. mini_httpd在RedHat 5下安装

    1.安装mini_httpdcd /usr/src/redhat/SOURCES wget http://www.acme.com/software/mini_httpd/mini_httpd-1.1 ...