砖块Klo bzoj-1112 POI-2008

题目大意:$N$柱砖,希望有连续$K$柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

注释:$1\le k\le n\le 10^5$,$0\le height_i\le 10^6$。


想法:

如果我们想让以$i$为左端点的连续$k$柱合法,

假设最后的高度是$H$,那么我们的代价就是:

$\sum\limits_{j=i}^{i+k-1} |h_j-H|$。

显然当$H$为这$k$个数的中位数的时候当前区间的代价最小。

至此,我们就可以弄一个平衡树。

每次加入$i+k$然后把开头的$i$删去,求出当前区间的中位数更新答案即可。

Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std; typedef long long ll;
struct Node
{
int ls,rs,size; ll sum,val,key;
}a[N];
struct par {int x,y;};
ll num[N]; int root,cnt;
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
ll rd() {ll x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
inline int newnode(ll val)
{
int x=++cnt;
a[x].size=1; a[x].ls=a[x].rs=0;
a[x].val=a[x].sum=val; a[x].key=rand()*rand();
return x;
}
inline void pushup(int x)
{
int ls=a[x].ls,rs=a[x].rs;
a[x].size=1; a[x].sum=a[x].val;
if(ls) a[x].size+=a[ls].size,a[x].sum+=a[ls].sum;
if(rs) a[x].size+=a[rs].size,a[x].sum+=a[rs].sum;
}
int merge(int x,int y)
{
if(!x||!y) return x|y;
if(a[x].key>a[y].key)
{
a[x].rs=merge(a[x].rs,y); pushup(x);
return x;
}
else
{
a[y].ls=merge(x,a[y].ls); pushup(y);
return y;
}
}
par split(int x,int k)
{
if(!k) return (par){0,x};
int ls=a[x].ls,rs=a[x].rs;
if(k==a[ls].size)
{
a[x].ls=0; pushup(x);
return (par){ls,x};
}
else if(k==a[ls].size+1)
{
a[x].rs=0; pushup(x);
return (par){x,rs};
}
else if(k<a[ls].size)
{
par t=split(ls,k);
a[x].ls=t.y; pushup(x);
return (par){t.x,x};
}
else
{
par t=split(rs,k-a[ls].size-1);
a[x].rs=t.x; pushup(x);
return (par){x,t.y};
}
}
par split_val(int x,int val)
{
if(!x) return (par){0,x};
int ls=a[x].ls,rs=a[x].rs;
if(a[x].val>=val)
{
par t=split_val(ls,val);
a[x].ls=t.y; pushup(x);
return (par){t.x,x};
}
else
{
par t=split_val(rs,val);
a[x].rs=t.x; pushup(x);
return (par){x,t.y};
}
}
void delet(ll val)
{
par t1=split_val(root,val),t2=split(t1.y,1);
root=merge(t1.x,t2.y);
}
void insert(ll val)
{
par t1=split_val(root,val);
root=merge(t1.x,merge(newnode(val),t1.y));
}
void output(int x)
{
int ls=a[x].ls,rs=a[x].rs;
if(ls) output(ls);
printf("%lld ",a[x].val);
if(rs) output(rs);
}
int main()
{
srand(12378);
int n=rd(),k=rd(); for(int i=1;i<=n;i++) num[i]=rd();
for(int i=1;i<=k;i++) insert(num[i]);
int id=(k+1)/2;
par t1=split(root,id-1),t2=split(t1.y,1);
ll ans=(a[t2.x].val*a[t1.x].size-a[t1.x].sum)+(a[t2.y].sum-a[t2.x].val*a[t2.y].size);
int dic=k,dic_val=a[t2.x].val;
root=merge(t1.x,merge(t2.x,t2.y));
for(int i=k+1;i<=n;i++)
{
insert(num[i]); delet(num[i-k]);
// printf("%d : ",i); output(root); puts("");
par t1=split(root,id-1),t2=split(t1.y,1);
ll now=(a[t2.x].val*a[t1.x].size-a[t1.x].sum)+(a[t2.y].sum-a[t2.x].val*a[t2.y].size);
if(now<ans) dic=i,ans=now,dic_val=a[t2.x].val;
root=merge(t1.x,merge(t2.x,t2.y));
}
for(int i=dic-k+1;i<=dic;i++) num[i]=dic_val;
printf("%lld\n",ans);
// for(int i=1;i<=n;i++) printf("%lld\n",num[i]);
// puts("");
return 0;
}

小结:平衡树的应用还是较为广泛的。

[bzoj1112][POI2008]砖块Klo_非旋转Treap的更多相关文章

  1. BZOJ1112[POI2008]砖块Klo——非旋转treap

    题目描述 N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任 ...

  2. [BZOJ1112][POI2008]砖块Klo

    [BZOJ1112][POI2008]砖块Klo 试题描述 N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另 ...

  3. [bzoj3173]最长上升子序列_非旋转Treap

    最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...

  4. 关于非旋转treap的学习

    非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\) split 作用:将原 ...

  5. [Codeforces702F]T-Shirts——非旋转treap+贪心

    题目链接: Codeforces702F 题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限.现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买 ...

  6. BZOJ5063旅游——非旋转treap

    题目描述 小奇成功打开了大科学家的电脑. 大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序.初 始时,序列为1,2,...,n. 接着,大科学家进行m次操作来打乱顺序.每次操作有6步: ...

  7. BZOJ3223文艺平衡树——非旋转treap

    此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...

  8. BZOJ3224普通平衡树——非旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

  9. [NOIP]2017列队——旋转treap/非旋转treap

    Sylvia 是一个热爱学习的女孩子.  前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m.  为了便 ...

随机推荐

  1. 个人复习记录之-js

    1变量:内存中储存一个数据的储存空间. 使用:声明,赋值,取值.注 不能以数字开头,不能用保留字 *声明提前:在程序正式执行前,都会将所有var声明的变量提前到开始位置,集中创建***赋值留在原地** ...

  2. addslashes,stripslashes

    官方介绍: (PHP 4, PHP 5) addslashes — 使用反斜线引用字符串 返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线.这些字符是单引号(’).双引号(”). ...

  3. Winform中ListView鼠标移动使用toolTip显示信息

    今天在做一个酒店管理系统的时候用到了ListView,突然想到是否能够当鼠标移动到某一项的时候给出具体房间的信息呢! 首先设置Listview的MouseMove事件 1.获取当前坐标的项 ListV ...

  4. PostgreSQL 数据库错误状态编号解释[附带列表

    PostgreSQL 服务器发出的所有消息都赋予了五个字符的错误代码, 这些代码遵循 SQL 的 "SQLSTATE" 代码的习惯.需要知道发生了什么错误条件的应用通常应该测试错误 ...

  5. (转) 淘淘商城系列——CMS内容管理系统工程搭建

    http://blog.csdn.net/yerenyuan_pku/article/details/72825801 淘淘商城系列——CMS内容管理系统工程搭建 上文我们一起搭建了表现层中的商城门户 ...

  6. redisd的非持久化配置

    如何关闭redis持久化?我的需求是只把redis当作缓存来用,所以持久化到硬盘对我的需求来说没有意义. 修改redis配置文件,redis.conf 第115行左右. 1.注释掉原来的持久化规则 # ...

  7. CAD使用DeleteXData删除数据(com接口)

    主要用到函数说明: MxDrawEntity::DeleteXData 删除扩展数据,详细说明如下: 参数 说明 pzsAppName 删除的扩展数据名称,如果为空,删除所有扩展数据 c#代码实现如下 ...

  8. 时间戳显示格式为几天前、几分钟前、几秒前---vue过滤器

    //时间显示问题(几天前.几分钟前)Vue.filter('fomatTime', function (valueTime) { if(valueTime){ var newData = Date.p ...

  9. CentOS 初体验十四:阿里云安装Gitlab

    网址:https://about.gitlab.com/install/#centos-7 https://blog.csdn.net/zhaoyanjun6/article/details/7914 ...

  10. 【C语言】控制台窗口图形界面编程(七):鼠标事件

    目录 00. 目录 01. INPUT_RECORD结构 02. MOUSE_EVENT_RECORD结构 03. ReadConsoleInput函数 04. 示例程序 00. 目录 01. INP ...