[BZOJ 4071] 巴邻旁之桥
Link:
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] 巴邻旁之桥的更多相关文章
- 【BZOJ4071】[Apio2015]巴邻旁之桥 Treap
[BZOJ4071][Apio2015]巴邻旁之桥 Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 ...
- 4071: [Apio2015]巴邻旁之桥
Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...
- BZOJ4071 & 洛谷3644 & UOJ112:[APIO2015]巴邻旁之桥——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4071 https://www.luogu.org/problemnew/show/P3644 ht ...
- [bzoj4071] [Apio2015]巴邻旁之桥
Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...
- 【BZOJ4071】【APIO2015】巴邻旁之桥
题意: Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 1 ...
- bzoj 4071: [Apio2015]巴邻旁之桥【splay】
用权值线段树会容易一些并快一些,但是想复健一下splay所以打了splay 然后果然不会打了. 解题思路: 首先把家和办公室在同一侧的提出来直接加进答案里: 对于k=1,直接选所有办公室和家的中位数即 ...
- [APIO2015]巴邻旁之桥
Bzoj权限题 luogu题面 先去掉同边的 首先k==1,即求一个点j 使\(\sum_{i\in A} |D_i - D_j| + \sum_{i\in B} |D_i - D_j|\)最小 因为 ...
- 【LOJ】#2888. 「APIO2015」巴邻旁之桥 Palembang Bridges
题解 发现我们选择一座桥会选择力\(\frac{s + t}{2}\)较近的一座桥 然后我们只需要按照\(s + t\)排序,然后枚举断点,左边取所有s和t的中位数,右边同理 动态求中位数用平衡树维护 ...
- 「APIO2015」巴邻旁之桥 Palembang Bridges
贪心 先转化一下题意 首先如果一个人的家和办公室在河同一侧那么建桥的时候不用去考虑它,最终把答案加上即可 在河两侧的家和办公室互换不影响答案,那么可以把这个抽象到一个区间$[l,r]$,距离就是$|l ...
随机推荐
- Spring Cloud全家桶主要组件及简要介绍
一.微服务简介 微服务是最近的一两年的时间里是很火的一个概念.感觉不学习一下都快跟不上时代的步伐了,下边做一下简单的总结和介绍. 何为微服务?简而言之,微服务架构风格这种开发方法,是以开发一组小型服务 ...
- 读书笔记 ~ Nmap渗透测试指南
记录Nmap选项及脚本使用,仅供参考... 除了端口扫描,好像其它脚本都比较鸡肋,用途感觉应该没有专用的小工具好用,不过还是可以看看,选项和脚本还是相当的丰富的. Nmap 使用帮助 starnigh ...
- Linux Deploy 使用 Repository部署Linux系统
Linux Deploy 使用 Repository部署Linux系统 为了解决镜像不稳定导致包下载错误,能得到一个稳定环境,可以使用linux deploy导出功能. 这里提供两个制作好的包 用户名 ...
- VC字体对话框的初始化
本代码需要先添加类成员 LOGFONT lf; void CMyDlg::OnButton3() { // TODO: Add your control notification handler c ...
- webgote的例子(5)Sql注入(Blog)
SQL Injection - Stored (Blog) (本章内容):留言板的注入 看到这个页面先看以下这个页面是做什么的.进行正常的写入发现我每写一句话,其内容都会写到下面的entry里面 在尝 ...
- 【appium】根据UIAutomator定位元素等等资料
https://www.cnblogs.com/paulwinflo/p/4742529.html http://www.cnblogs.com/meitian/p/6103391.html http ...
- SQLite3数据库的操作
数据库的操作 我们在这个项目中使用的是SQLITE3数据库软件. 通过使用SQLITE3进行创建数据库,创建表,插入记录,查询记录,更新记录,关闭数据库等操作来实现将相应的数据存入数据库中. 打开数据 ...
- ubuntu10.04 svn安装方法
ubuntu10.04 svn安装方法:sudo apt-get install subversion sudo apt-get install libneon27-dev orsudo apt-ge ...
- MySQL登录问题1045 (28000)处理步骤【原创】
MySQL登录问题1045 (28000) 俩台服务器主从复制,从的同步账号无法远程登录主服务器.报错ERROR 1045 (28000): Access denied for user 'root ...
- Gym 101081K Pope's work
题目链接:Gym - 101081K 题意:给n个箱子,每个箱子有一个重量W和一个承重R,表示它上面能放最多R-W的重量.问最多能把多少箱子堆到一堆. 思路:发现在一堆箱子里,两个箱子交换位置,对其他 ...