HDU 3473 Minimum Sum (划分树求区间第k大带求和)(转)
题意:在区间中找一个数,求出该区间每个数与这个数距离的总和,使其最小
找的数字是中位数(若是偶数个,则中间随便哪个都可)接着找到该区间比此数大的数的总和
区间中位数可以使用划分树,然后在其中记录:每层的 1-i 中划分到左区间的总和
划分树:
划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k大值 。
划分树和归并树都是用线段树作为辅助的,原理是基于快排 和归并排序 的。
划分树的建树过程基本就是模拟快排过程,取一个已经排过序的区间中值,然后把小于中值的点放左边,大于的放右边。并且记录d层第i个数之前(包括i)小于中值的放在左边的数。
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- using namespace std;
- #define dir(a,b) (a>>b)
- const int Max=1e5+;
- int orval[Max];
- int dsegtr[][Max];//记录第i层划分树的序列
- int lele[][Max];//记录第i层的1-i划分到左子树的元素个数(包括i)
- long long sum[][Max],psum[Max],lsum;//每层的1-i中划分到左区间的总和
- void Create(int sta,int enn,int cur)
- {
- int mid=dir(sta+enn,);
- int lsame=mid-sta+;//此区间左边不小于orval[mid]的个数
- int lsta=sta,rsta=mid+;
- for(int i=sta; i<=mid; ++i)
- {
- if(orval[i]<orval[mid])
- lsame--;
- }
- for(int i=sta; i<=enn; ++i)//给下一层赋值
- {
- sum[cur][i]=sum[cur][i-];
- if(i==sta)
- {
- lele[cur][i]=;//表示[l, i]内有多少个数分到左边
- }
- else
- {
- lele[cur][i]=lele[cur][i-];
- }
- if(dsegtr[cur][i]==orval[mid])
- {
- if(lsame)
- {
- sum[cur][i]+=dsegtr[cur][i];
- lsame--;
- lele[cur][i]++;
- dsegtr[cur+][lsta++]=dsegtr[cur][i];//相当于移动元素到左边
- }
- else
- {
- dsegtr[cur+][rsta++]=dsegtr[cur][i];//相当于移动元素到右边
- }
- }
- else if(dsegtr[cur][i]<orval[mid])
- {
- sum[cur][i]+=dsegtr[cur][i];
- lele[cur][i]++;
- dsegtr[cur+][lsta++]=dsegtr[cur][i];
- }
- else
- {
- dsegtr[cur+][rsta++]=dsegtr[cur][i];
- }
- }
- if(sta==enn)
- return;
- Create(sta,mid,cur+);
- Create(mid+,enn,cur+);
- return;
- }
- int Query(int sta,int enn,int cur,int lef,int rig,int k)
- {
- int lsame;//[sta, lef)内将被划分到左子树的元素数目
- int rsame;//[lef,rig]内将被划分到左子树的元素数目 关键
- int mid=dir(sta+enn,);
- if(sta==enn)
- return dsegtr[cur][sta];
- if(sta==lef)//特判
- {
- lsame=;
- rsame=lele[cur][rig];
- }
- else
- {
- lsame=lele[cur][lef-];
- rsame=lele[cur][rig]-lsame;
- }
- if(k<=rsame)
- {
- return Query(sta,mid,cur+,sta+lsame,sta+lsame+rsame-,k);//关键
- }
- else
- {
- lsum+=sum[cur][rig]-sum[cur][lef-];//所求值不在左区间
- return Query(mid+,enn,cur+,mid-sta++lef-lsame,mid-sta++rig-lsame-rsame,k-rsame);//关键
- }
- }
- long long Solve(long long temp,int rig,int lef,int k)
- {
- long long resr=psum[rig]-psum[lef-]-lsum-temp-(long long)(rig-lef+-k)*temp;
- long long resl=(long long)(k-)*temp-lsum;
- return resr+resl;
- }
- int main()
- {
- int n,m,t,coun=;
- int lef,rig;
- scanf("%d",&t);
- while(t--)
- {
- scanf("%d",&n);
- for(int i=;i<;++i)
- sum[i][]=0ll;
- psum[]=0ll;
- for(int i=; i<=n; ++i)
- {
- scanf("%d",&orval[i]);
- psum[i]=psum[i-]+orval[i];
- dsegtr[][i]=orval[i];
- sum[][i]=sum[][i-]+orval[i];
- }
- sort(orval+,orval+n+);
- Create(,n,);
- scanf("%d",&m);
- printf("Case #%d:\n",++coun);
- for(int i=; i<m; ++i)
- {
- lsum=0ll;
- scanf("%d %d",&lef,&rig);
- lef++,rig++;
- int temp=Query(,n,,lef,rig,(rig-lef+>>));
- printf("%I64d\n",Solve(temp,rig,lef,(rig-lef+>>)));
- }
- printf("\n");
- }
- return ;
- }
参考:http://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html
HDU 3473 Minimum Sum (划分树求区间第k大带求和)(转)的更多相关文章
- [hdu2665]Kth number(划分树求区间第k大)
解题关键:划分树模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cs ...
- HDU 3473 Minimum Sum 划分树,数据结构 难度:1
http://acm.hdu.edu.cn/showproblem.php?pid=3473 划分树模板题目,需要注意的是划分树的k是由1开始的 划分树: 参考:http://blog.csdn.ne ...
- HDU 3473 Minimum Sum 划分树
题意: 给出一个长度为\(n(1 \leq n \leq 10^5)\)的序列\(a\) 有若干次查询l r:找到一个\(x\)使得\(\sum \limits_{l \leq i \leq r} \ ...
- [csu/coj 1080]划分树求区间前k大数和
题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...
- HDOJ题目4417 Super Mario(划分树求区间比k小的个数+二分)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- [poj2104]kth-number(归并树求区间第k大)
复杂度:$O(nlog^3n)$ #include<cstdio> #include<cstring> #include<algorithm> #include&l ...
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
- POJ2761---Feed the dogs (Treap求区间第k大)
题意 就是求区间第k大,区间 不互相包含. 尝试用treap解决一下 第k大的问题. #include <set> #include <map> #include <cm ...
- HDU 3473 Minimum Sum (划分树)
题意:给定一个数组,有Q次的询问,每次询问的格式为(l,r),表示求区间中一个数x,使得sum = sigma|x - xi|最小(i在[l,r]之间),输出最小的sum. 思路:本题一定是要O(nl ...
随机推荐
- iOS-ASIHTTPRequest框架学习
本文转载至 http://www.cnblogs.com/A-Long-Way-Chris/p/3539679.html 前段时间在公司的产品中支持了够快网盘,用于云盘存储. 在这个过程中,学习到了很 ...
- knockoutJs在移动设备上有时无法更新控件值
最近在用cordova(phonegap)写一个移动app,表单比较复杂,用了knockoutJs作为前端的MVVM框架进行数据绑定. 但是发现有时候(其实是每次)如果最后在input中编辑一个值,然 ...
- 子单元通过 prop 接口与父单元进行了良好的解耦
https://cn.vuejs.org/v2/guide/#起步 现在,我们可以使用 v-bind 指令将待办项传到循环输出的每个组件中: <div id="app-7"& ...
- VS2015 如何打印出 类的内存布局?
项目->属性->C/C++->命令行 添加如下内容: /d1 reportAllClassLayout [XXX] XXX 可选,代表源文件名,例如 main.cpp 或 /d1 r ...
- 使用Sentry集中化日志管理
在调试程序中,通过日志分期来排查BUG是一个重要手段,它可以说是程序调试的利器. 关于日志管理 随着应用组件变多,那么各coder对输出日志五花八门,有写入stdout,有写stderr, 有写到sy ...
- 解决Vue的表格中,expand只有某些行需要展开的问题。
element UI里的表格里,type="expand"的话,所有行都有展开的选项,然而实际中有些行根据判断不需要展开,而element目前对这个问题还不是很友好,现在有个可以通 ...
- python并发编程&IO模型
一 IO模型介绍 为了更好地了解IO模型,可先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(n ...
- ApexSQL Log 从意外UPDATE和DELETE操作中恢复SQL Server数据
下载地址:https://www.apexsql.com/download.aspx 如何从意外UPDATE和DELETE操作中恢复SQL Server数据 ApexSQL Log 从意外UPDATE ...
- ApexSQL Recover 恢复一个被drop的表的数据
没有备份的情况下恢复一个被drop的表的数据 ApexSQL Recover 恢复一个被drop的表的数据 转自:https://solutioncenter.apexsql.com/zh/%E6%B ...
- SUBMIT RM07DOCS【MB51】 获取返回清单,抓取标准报表数据
*&---------------------------------------------------------------------* *& Report YT_SUBMIT ...