BZOJ 1112 [POI2008]砖块Klo Treap
2015-09-14 20:17
417 查看
题意:链接
方法: Treap
解析:
我们线性扫区间,然后每个区间的中位数肯定是这个区间的选取的高度。
搞出这个高度后我们要将这个区间内的所有的数与选取的高度作差取绝对值求和。
所以转化成,我们需要一种数据结构支持删点,加点,找排名为rnk的数,询问部分求和。
所以上个Treap就好了。
至于求和,记个sum,比中位数小的用中位数乘个数减求和,比中位数大的用求和减中位数乘个数。
说了这么多其实就是个水题- -!代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define N 100010 using namespace std; typedef long long ll; int n,k; ll h ; int tot; int size,root; struct node { int l,r,rnd; ll siz,w,v,sum; }tr ; void pushup(int &rt) { tr[rt].siz=1+tr[tr[rt].l].siz+tr[tr[rt].r].siz; tr[rt].sum=tr[rt].v+tr[tr[rt].l].sum+tr[tr[rt].r].sum; } void lturn(int &rt) { int t=tr[rt].r; tr[rt].r=tr[t].l; tr[t].l=rt; tr[t].siz=tr[rt].siz; pushup(rt); rt=t; } void rturn(int &rt) { int t=tr[rt].l; tr[rt].l=tr[t].r; tr[t].r=rt; tr[t].siz=tr[rt].siz; pushup(rt); rt=t; } void insert(int &rt,ll v) { if(!rt) { rt=++size; tr[rt].siz=1; tr[rt].v=v,tr[rt].sum=v; tr[rt].rnd=rand(); return; } tr[rt].siz++; if(v<=tr[rt].v) { insert(tr[rt].l,v); if(tr[tr[rt].l].rnd<tr[rt].rnd)rturn(rt); }else { insert(tr[rt].r,v); if(tr[tr[rt].r].rnd<tr[rt].rnd)lturn(rt); } pushup(rt); } void del(int &rt,ll v) { if(!rt)return; tr[rt].siz--; if(tr[rt].v==v) { if(tr[rt].l*tr[rt].r==0){rt=tr[rt].l+tr[rt].r;return;} if(tr[tr[rt].l].rnd<tr[tr[rt].r].rnd)rturn(rt),del(tr[rt].r,v); else lturn(rt),del(tr[rt].l,v); }else if(v<tr[rt].v)del(tr[rt].l,v); else del(tr[rt].r,v); pushup(rt); } ll q_val(int rt,int rnk) { if(tr[tr[rt].l].siz+1==rnk)return tr[rt].v; else if(rnk<tr[tr[rt].l].siz+1)return q_val(tr[rt].l,rnk); else return q_val(tr[rt].r,rnk-tr[tr[rt].l].siz-1); } ll q_sum_pre(int rt,int rnk) { if(!rnk)return 0; if(tr[tr[rt].l].siz+1==rnk)return tr[tr[rt].l].sum+tr[rt].v; else if(rnk<tr[tr[rt].l].siz+1)return q_sum_pre(tr[rt].l,rnk); else return tr[tr[rt].l].sum+tr[rt].v+q_sum_pre(tr[rt].r,rnk-tr[tr[rt].l].siz-1); } ll q_sum_sub(int rt,int rnk) { if(!rnk)return 0; if(tr[tr[rt].l].siz+1==rnk)return tr[tr[rt].r].sum+tr[rt].v; else if(rnk<tr[tr[rt].l].siz+1)return tr[tr[rt].r].sum+tr[rt].v+q_sum_sub(tr[rt].l,rnk); else return q_sum_sub(tr[rt].r,rnk-tr[tr[rt].l].siz-1); } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%lld",&h[i]); ll ans=0x3f3f3f3f3f3f3f3fll; for(int i=1;i<=n;i++) { if(i<k)insert(root,h[i]); else if(i==k) { insert(root,h[i]); ll mid=q_val(root,(k+1)>>1); ll sum1=q_sum_pre(root,(k+1)>>1); ll sum2=q_sum_sub(root,((k+1)>>1)+1); ans=min(ans,mid*((k+1)>>1)-sum1+sum2-mid*(k-((k+1)>>1))); }else { del(root,h[i-k]); insert(root,h[i]); ll mid=q_val(root,(k+1)>>1); ll sum1=q_sum_pre(root,(k+1)>>1); ll sum2=q_sum_sub(root,((k+1)>>1)+1); ans=min(ans,mid*((k+1)>>1)-sum1+sum2-mid*(k-((k+1)>>1))); } } printf("%lld\n",ans); }
相关文章推荐
- 前端优化
- (Dijkstra&Bellman-ford)POJ2387Til the Cows Come Home
- TCP/IP协议相关知识
- linux下追踪软件执行过程之cflow
- 字符串反转
- 二分法小程序的问题
- 二分法小程序的问题
- linux常用命令(28):gzip命令
- app选择不再提醒,对话框将不再提示
- soapui 自动化教程(二)
- linux Shell学习笔记3
- Android网络连接---多线程下载
- android网络连接Volley
- hdu4099(trie树,斐波那契数列)
- linux Shell学习笔记2
- JOS 系统调用的过程
- IAP_支付本地验证
- Linq学习from let where子句
- Java中什么时候使用构造方法
- 磁盘管理和文件系统管理