[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】915 E. Physical Education Lessons 线段树
[题目]E. Physical Education Lessons [题意]10^9范围的区间覆盖,至多3*10^5次区间询问. [算法]线段树 [题解]每次询问至多增加两段区间,提前括号分段后线段树 ...
- 浅析 Spring Aop
aop也是Spring里比较重要的一个点,最近把源码看了下,这里总结一下 使用上主要就下面的点注意下: 相关的Annotaion Around Before After AfterReturning ...
- 【leetcode 简单】第十二题 报数
报数序列是指一个整数序列,按照其中的整数的顺序进行报数,得到下一个数.其前五项如下: 1. 1 2. 11 3. 21 4. 1211 5. 111221 1 被读作 "one 1&quo ...
- PHPMailer发送邮件(一)
Github 地址:(已更新,适用于旧版) PHPMailer : https://github.com/PHPMailer/PHPMailer 一.基本要求 Web访问正常(apache可以正常访问 ...
- 二. Jmeter--参数化
1. 新建一个txt文件,输入些数据, 一行有四个数据,用逗号分隔. 保存的时候Encoding选择Unicode 2.添加一个Thread Group, 然后添加一个CSV Data Set Con ...
- 【IDEA】IDEA中maven项目pom.xml依赖不生效解决
问题: 今天在web项目中需要引入poi相关jar包.查看之下才发现pom.xml中的依赖虽然已经下载到了本地仓库 repository,但是却没有加入到项目路径的 Extenal Libraries ...
- docker安装总结 linux红帽系列
由于Docker限制分为两个版本CE和EE,所以之前yum里面的docker是老版本,需要先进行卸载,现在的包名叫做docker-ce yum remove docker docker-common ...
- grep 中的正则表达式【转】
正则表达式 正则表达式就是用于匹配每行输入的一种模式,模式是指一串字符序列.下面是范例: ^w1 w1|w2 [^ ] grep 正则表达式示例 在 /etc/passswd 目录中搜索 'vivek ...
- 26_Python的内置函数
The Python interpreter has a number of functions and types built into it that are always available.P ...
- 「caffe编译bug」python/caffe/_caffe.cpp:10:31: fatal error: numpy/arrayobject.h: No such file or directory
在Makefile.config找到PYTHON_INCLUDE,发现有点不同: PYTHON_INCLUDE := /usr/include/python2.7 \ /usr/lib ...