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 ...
随机推荐
- <转> python的垃圾回收机制
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾.在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的 ...
- 【BZOJ2506】calc 分段+vector+莫队
[BZOJ2506]calc Description 给一个长度为n的非负整数序列A1,A2,…,An.现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且A ...
- 【BZOJ2770】YY的Treap 结论+线段树
[BZOJ2770]YY的Treap Description 志向远大的YY小朋友在学完快速排序之后决定学习平衡树,左思右想再加上SY的教唆,YY决定学习Treap.友爱教教父SY如砍瓜切菜般教会了Y ...
- 《从零开始学Swift》学习笔记(Day 33)——属性观察者
原创文章,欢迎转载.转载请注明:关东升的博客 为了监听属性的变化,Swift提供了属性观察者.属性观察者能够监听存储属性的变化,即便变化前后的值相同,它们也能监听到. 属性观察者主要有以下两个: l ...
- DataTable数据筛选
DataView view = newDt.DefaultView;view.Sort = "Description asc,replyEnd desc";DataTable ta ...
- 如何用 JavaScript 控制 Arduino?
Arduino 运行 C 语言,而主控端运行 JavaScript,一次要编写和维护两种程序.既然浏览器和服务器都用 JavaScript,若 Arduino 也能用 JavaScript 控制,那岂 ...
- nodejs开发解决方案
1.2. 统一环境 开发环境 nvm nrm nodejs 0.10.38 node-inspector 部署环境 nvm nrm iojs 2.x pm2 nginx 异步流程控制:Promise是 ...
- django的模板系统过滤器笔记
-------------------django内建的过滤器-------------------1.add 使用形式为:{{ value | add: "2"}}意义:将val ...
- 剑指offer 面试25题
面试25题:题目:合并两个排序的链表 题:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 解题思路:递归,并需注意对空链表单独处理. 解题代码: # -* ...
- 对称加密&非对称加密
对称密钥密码算法的特点: 算法简单,加/解密速度快,但密钥管理复杂,不便于数字签名: 非对称密钥密码算法的特点: 算法复杂,加/解密速度慢,密钥管理简单,可用于数字签名. 所以将两者结合起来,形成混合 ...