BZOJ 1112 [POI2008]砖块Klo Treap

2024-03-30 16:48
文章标签 bzoj 砖块 treap poi2008 klo 1112

本文主要是介绍BZOJ 1112 [POI2008]砖块Klo Treap,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

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

Input

第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

Output

最小的动作次数

Sample Input

5 3
3
9
2
3
1

Sample Output

2

HINT

原题还要求输出结束状态时,每柱砖的高度.本题略去.






传送门

一个结论就是区间里面取中位数,总差值肯定最小。

画个数轴很容易证明出来的。

然后这题就变成了维护长度为k的区间的中位数,并且求出其它数和其差的绝对值之和。

可以用一个平衡树去搞,

维护结点的子树大小、子树sum;

然后求出所有比中位数小的,花费是中位数减去它们;

比中位数大的,花费是它们减去中位数。

每次区间变动,delete最前面的、insert最后面的即可。


明明打了重复结点看作一个点的做法……

竟然计算sum的时候总是漏点什么= =

话说treap真的比splay快好多= =



#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100005;
int n,K,tot,root;
int H[N];
ll ans;
struct Treap{int sz[N],occ[N],l[N],r[N],rnd[N];ll sum[N],val[N];void up(int &k){sz[k]=sz[l[k]]+sz[r[k]]+occ[k];sum[k]=sum[l[k]]+sum[r[k]]+val[k]*occ[k];}void rturn(int &k){int t=l[k];l[k]=r[t],r[t]=k;up(k),k=t,up(k);}void lturn(int &k){int t=r[k];r[k]=l[t],l[t]=k;up(k),k=t,up(k);}void insert(int &k,int x,int &tot){if (!k){k=++tot;sz[k]=occ[k]=1,l[k]=r[k]=0;sum[k]=val[k]=(ll)x,rnd[k]=rand();return;}sz[k]++,sum[k]+=(ll)x;if (x==val[k]){occ[k]++;return;}if (x<=val[k]){insert(l[k],x,tot);if (rnd[l[k]]<rnd[k]) rturn(k);} else{insert(r[k],x,tot);if (rnd[r[k]]<rnd[k]) lturn(k);}}void del(int &k,int x){if (!k) return;if (val[k]==x){if (occ[k]>1){sum[k]-=(ll)x,sz[k]--,occ[k]--;return;}if (!l[k] || !r[k]){k=l[k]^r[k];return;}if (rnd[l[k]]<rnd[r[k]]) rturn(k);else lturn(k);del(k,x);return;}sz[k]--,sum[k]-=(ll)x;if (x<=val[k]) del(l[k],x);else del(r[k],x);}ll SmallSum(int &k,int x){if (!k) return 0LL;if (val[k]<=x) return SmallSum(r[k],x)+sum[l[k]]+val[k]*occ[k];else return SmallSum(l[k],x);}ll BigSum(int &k,int x){if (!k) return 0LL;if (val[k]>x) return BigSum(l[k],x)+sum[r[k]]+val[k]*occ[k];else return BigSum(r[k],x);}int query_num(int &k,int x){if (!k) return 0;if (sz[l[k]]>=x) return query_num(l[k],x);if (sz[l[k]]+occ[k]<x) return query_num(r[k],x-sz[l[k]]-occ[k]);return val[k];}void query_pre(int &k,int x){if (!k) return;if (val[k]<=x){ans+=sz[l[k]]+occ[k],query_pre(r[k],x);}else query_pre(l[k],x);}void query_suc(int &k,int x){if (!k) return;if (val[k]>x){ans+=sz[r[k]]+occ[k],query_suc(l[k],x);}else query_suc(r[k],x);}
}tr;
int middle(){return tr.query_num(root,(K+1)>>1);
}
ll countans(int mid){ll tres;ans=0LL,tr.query_pre(root,mid);tres=ans*mid-tr.SmallSum(root,mid);ans=0LL,tr.query_suc(root,mid);tres+=tr.BigSum(root,mid)-ans*mid;return tres;
}
int main(){srand(283810);scanf("%d%d",&n,&K);for (int i=1;i<=n;i++) scanf("%d",&H[i]);tot=root=0;for (int i=1;i<=K;i++) tr.insert(root,H[i],tot);ll res=countans(middle());for (int i=K+1;i<=n;i++){tr.del(root,H[i-K]);tr.insert(root,H[i],tot);res=min(res,countans(middle()));}printf("%lld\n",res);return 0;
}

这篇关于BZOJ 1112 [POI2008]砖块Klo Treap的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/862029

相关文章

FHQ Treap模版(luogu P3369)

FHQ Treap模版(自用),带注释 #include<bits/stdc++.h>using namespace std;const int N=1e5+10;int n,root,idx;struct node{int l,r;int val,key,size;}tr[N];int getnew(int v){tr[++idx].val=v;//权值tr[idx].key=rand(

【BZOJ】1324 Exca王者之剑 最大权独立集

传送门:【BZOJ】1324  Exca王者之剑 题目分析:赤裸裸的最大权独立集。。。最小割解决 代码如下: #include <cstdio>#include <vector>#include <cstring>#include <algorithm>using namespace std ;#define REP( i , a , b ) for ( int

【BZOJ】1026: [SCOI2009]windy数 数位DP

传送门:【BZOJ】1026: [SCOI2009]windy数 题目分析:数位DP水题。 代码如下: #include <stdio.h>#include <cstring>#include <algorithm>#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )#define For( i ,

【BZOJ】2152: 聪聪可可 点分治

传送门:【BZOJ】2152: 聪聪可可 题目分析:记录权值和%3的路径的个数。。。然后去重。。没了。。 代码如下: #include <vector>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std ;typedef lo

BZOJ 2440 2301 莫比乌斯应用

http://www.lydsy.com/JudgeOnline/problem.php?id=2440 Description 小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些 数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而 这丝毫不影响他对其他数的热爱。  这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一 个小X讨厌

BZOJ 3732: Network(最小生成树+倍增)

题目链接 题意:给出一个图,每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少 很明显最终查询的边一定是在最小生成树里面的,先跑出最小生成树,然后,可以树链剖分,也可以使用倍增来计算 #include<bits/stdc++.h>using namespace std;#define cl(a,b) memset(a,b,sizeof(a))#define

1112:三角形划分区域

题目描述 用N个三角形最多可以把平面分成几个区域? 输入格式 输入数据的第一行是一个正整数T(1<=T<=10000),表示测试数据的数量。然后是T组测试数据,每组测试数据只包含一个正整数N(1<=N<=10000)。 输出 对于每组测试数据,请输出题目中要求的结果。 样例输入 2 1 2 样例输出 2 8 #include<stdio.h>int main(){int

BZOJ 2038 小Z的袜子(hose) (莫队离线)

题目地址:BZOJ 2038 裸的莫队算法。 代码如下: #include <iostream>#include <string.h>#include <math.h>#include <queue>#include <algorithm>#include <stdlib.h>#include <map>#include <set>#include <stdio.h>#in

BZOJ 2152 聪聪可可 (树上点分治)

题目地址:BZOJ 2152 找有多少对权值和为3的倍数的点。最简单的点分治。 代码如下: #include <iostream>#include <string.h>#include <math.h>#include <queue>#include <algorithm>#include <stdlib.h>#include <map>#include <set>#incl

BZOJ 3530 数数【AC自动机+数位dp】

[Sdoi2014]数数 简单数位dp+简单AC自动机 反正数位DP是队友写的 AC自动机要记录两个值,一个是是否为一个串的结束,即不合法状态,一个是前缀零的情况。 // whn6325689// Mr.Phoebe// http://blog.csdn.net/u013007900#include <algorithm>#include <iostr