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 ...
随机推荐
- 第一篇:尽量多的以 const/enum/inline 替代 #define
前言 在面向过程语言,如 C 语言中,#define 非常常见,也确实好用,值得提倡.但在如今面向对象的语言,如 C++ 语言中,#define 就要尽量少用了. 为何在 C++ 中就要少用了呢? 这 ...
- 转:: 刺鸟:用python来开发webgame服务端(4)
来源:http://ciniao.me/article.php?id=14 --------------- 刺鸟原创文章,转载请注明出处 前面的工作都已准备就绪,现在我们得来看看服务端怎么和客户 ...
- oracle 创建表并添加注释
CREATE TABLE t1(id varchar2(32) primary key,name VARCHAR2(32) ,age VARCHAR2(32) ) 添加表注释:COMMENT ON t ...
- getFullYear 方法
返回 Date 对象中用本地时间表示的年份值. dateObj.getFullYear() 必选项 dateObj 参数为 Date 对象. 说明要获取用全球标准时间 (UTC)表示的年份值,请使用 ...
- JS replace()方法替换变量(可以对变量进行全文替换)
转至:http://blog.sina.com.cn/s/blog_6552200b0102ve60.html 事情是这样的: 我要用 JS 替换一个多行文本的关键字 正常,没有变量的时候应该是这样: ...
- 扩展运算符和rest运算符
扩展运算符 扩展运算符用三个点号表示,功能是把数组或类数组对象展开成一系列用逗号隔开的值 一.拆分数组 扩展运算符可以直接把数组拆分成用逗号隔开的值 <template> <sect ...
- Linux vim编写程序时出现高亮字符,如何取消?
在“命令模式”下输入“:nohl“,再按回车,便可以取消高亮显示.
- Python操作——Redi
redis是一个key-value存储系统. 和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(列表).hash(哈希).set(集合).zset(有 ...
- 常用模块之hashlib,configparser,logging模块
常用模块二 hashlib模块 hashlib提供了常见的摘要算法,如md5和sha1等等. 那么什么是摘要算法呢?摘要算法又称为哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度固定 ...
- 曾经跳过的坑----jQuery mouseover与mouseenter,mouseout与mouseleave的区别
mouseover与mouseenter 不论鼠标指针穿过被选元素或其子元素,都会触发 mouseover 事件. 只有在鼠标指针穿过被选元素时,才会触发 mouseenter 事件. mouseou ...