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. 【BZOJ】3992: [SDOI2015]序列统计 NTT+生成函数

    [题意]给定一个[0,m-1]范围内的数字集合S,从中选择n个数字(可重复)构成序列.给定x,求序列所有数字乘积%m后为x的序列方案数%1004535809.1<=n<=10^9,3< ...

  2. 【洛谷 P3227】 [HNOI2013]切糕(最小割)

    题目链接 每层每个位置向下一层这个位置连边,流量为下一层这个位置的\(f\),源点向第一层连,流量第一层每个位置的费用,最后一层向汇点连,流量\(INF\). 这样就得到了\(P*Q\)条链,不考虑\ ...

  3. Sublime之插件的安装(一)

    由于最近刚换了一个工作,所以决定重新申请一个blog,把工作当中遇到的一些问题记录下来,方便自己下次忘记,也希望能与一起需要的小伙伴一起共勉. 如果有不同的观点或者是不同的看法,大家都可以畅谈,我一直 ...

  4. How to read source code[repost]

    https://github.com/benjycui/benjycui.github.io/blob/master/posts/how-to-read-open-source-javascript- ...

  5. nesC编程入门

    1.接口 NesC程序主要由各式组件(component)构成,组件和组件之间通过特定的接口(interface)互相沟通.一个接口内声明了提供相关服务的方法(C语言函数).例如数据读取接口(Read ...

  6. 初窥ThinkPHP

    MVC全称(Model View Controller) Model:模型(可以理解位数据库操作模型) View:视图(视图显示) Controller:(控制器) 简单的说框架就是一个类的集合.集合 ...

  7. 【Git/GitHub学习笔记】一键更新多个git仓库至远程

    因为同时在本地维护几个Github的仓库,每次更新后每个仓库要重复三步提交同步,有点麻烦. 发现可以写.sh文件来实现一键更新. 比如我要更新我的BlogBackup和CodeRepo两个仓库的代码如 ...

  8. 【BubbleCup X】D. Exploration plan

    这个题首先一眼能看出二分答案…… 毕竟连可爱的边界都给你了. 下面就是怎么check 首先预处理跑一遍floyed,预处理出最短路. 用网络流判断能否达到即可. #include<bits/st ...

  9. BZOJ 1975: [Sdoi2010]魔法猪学院——K短路,A*

    传送门 http://www.lydsy.com/JudgeOnline/problem.php?id=1975 题意&简要做法 一张有向图,求出最多的互不相同的路径,满足路径长度之和\(\l ...

  10. libuv 一 环境搭建, hello TTY

    引言 - 一时心起, libuv linux 搭建 有一天突然想起来想写个动画. 找了一下 ui 库太大. 后面想起以前弄过的 libuv. 但发现 libuv 相关资料也很少. 所以就有了这些内容. ...