[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 ...
随机推荐
- 【CodeForces】908 E. New Year and Entity Enumeration
[题目]E. New Year and Entity Enumeration [题意]给定集合T包含n个m长二进制数,要求包含集合T且满足以下条件的集合S数:长度<=m,非和与的结果都在集合中. ...
- 【leetcode 简单】第四十题 求众数
给定一个大小为 n 的数组,找到其中的众数.众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是非空的,并且给定的数组总是存在众数. 示例 1: 输入: [3,2,3] 输出: 3 ...
- NYOJ 202 红黑树 (二叉树)
题目链接 描述 什么是红黑树呢?顾名思义,跟枣树类似,红黑树是一种叶子是黑色果子是红色的树... 当然,这个是我说的... <算法导论>上可不是这么说的: 如果一个二叉查找树满足下面的红黑 ...
- [Leetcode] Longest Palindromic Subsequence
Longest Palindromic Subsequence 题解 题目来源:https://leetcode.com/problems/longest-palindromic-subsequenc ...
- 实现在点击asp:button按钮后,不刷新当前页面
方法1:return false <asp:Button ID="Button1" runat="server" Text="Button&qu ...
- 142.Linked List Cycle II---双指针
题目链接 题目大意:141题目的扩展,给出单链表,判断是否有环,如果有环,找出环的开始的结点,如果没有环,返回null. 法一(借鉴):在已经找出单链表环的基础上再找开始结点,要时刻记住这个环不一定是 ...
- 2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest, qualification stage
2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest, qualification stage A. Union of Doubly Link ...
- ntp 校时程序
//effect:send ntp packet and get the ntp packet ,make the time OK//2014.7.31 is OK//#include <sys ...
- POJ 2337 Catenyms(欧拉回(通)路:路径输出+最小字典序)
题目链接:http://poj.org/problem?id=2337 题目大意:给你n个字符串,只有字符串首和尾相同才能连接起来.请你以最小字典序输出连接好的单词. 解题思路:跟POJ1386一个意 ...
- wordpress技术-禁止订阅用户访问后台
begin主题虽然有个功能,但是只是少了入口,实际上测试还是可以进入后台的,那么怎么彻底解决呢?一时半会没思路,百度了下,果然有人贴出了代码. 把下面代码黏贴到主题的模板函数文件里即可: if ( i ...