终于要开始学习各种复杂的数据结构了。。明天早晨写一下picture 的求面积版然后就暂时不写线段树了
把网上clj的treap代码抄过来学习学习。。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<functional>
#include<vector>
#include<queue>
using namespace std;
const long MAXN=100010;
struct node
{
long key; // 随机数
long value; // 砖块高度
long size; // 左儿子数,右儿子数,加本身
long long sum; // 左儿子的和,右儿子的和,加本身大小
node*ch[2]; // 左儿子为0,右儿子为0
void update()
{
size=ch[0]->size+ch[1]->size+1;
sum=ch[0]->sum+ch[1]->sum+value;
}
node()
{
sum=size=0;
key=INT_MAX;
}
node(long _value);
}*null=new node;
inline long bigRand()
{
return (rand()*RAND_MAX)+rand(); // 随机数
}
node::node(long _value) // 创建一个高度为_value的节点
{
value=_value;
sum=value;
size=1;
ch[0]=ch[1]=null; // 左右儿子为空
key=bigRand(); // 随机数
}
struct treap
{
node*root;
treap()
{
root=null; // 根设为空
}
void rotate(node*&t,bool b) // 旋转
{
node*p = t->ch[b];
t->ch[b] = p->ch[!b];
p->ch[!b] = t;
t->update();
p->update();
if (root==t)
root=p;
t=p;
}
void insert(node*&t,long _value) // 往树里添加一个点
{
if (t==null) // 如果此时树为空
{
t=new node(_value); // 建立一个节点
return ;
}
bool dir=_value>t->value; // direction 方向
insert(t->ch[dir],_value); // 左右儿子
if (t->ch[dir]->key<t->key) rotate(t,dir); // 随机旋转
else t->update(); // 更新
}
void erase(node*&t,long _value) // 去掉一个值为_value的点
{
if (t==null) return ; // 如果此时树为空,返回(我估计没什么用)
if (t->value==_value) // 如果找到节点,把这个点旋转到叶子节点上
{
bool dir=t->ch[1]->key<t->ch[0]->key;
if (t->ch[dir]==null) // 如果到根节点上了,删除
{
delete t;
t=null;
return ;
}
rotate(t,dir); // 否则旋转
erase(t->ch[+dir],_value); // 此时t为当时的t的ch[dir]儿子,而现在指向的是t
t->update(); // 更新
return ;
}
bool dir=_value>t->value; // 当前节点不是需要的
erase(t->ch[dir],_value); // 递归进子树
t->update();
}
void calckth(long kth,long &x,long long &sum) // 中位数是第kth个,x返回中位数的值,sum返回小于中位数的和
{
sum=0; // for循环不断加左边的和
for (node*t=root;;) // 开一个t的指针为根
{
long cnt=t->ch[0]->size; // 左儿子的大小
if (kth>=cnt) // 如果需要大于等于左边的
sum+=t->ch[0]->sum; // sum加上左边节点的和
if (kth==cnt) // 如果正好
{
x=t->value; // x为中位数
return ;
}
if (kth>cnt) // 如果需要的比左儿子的多
{
kth-=cnt+1; // 减去左儿子个数和根
sum+=t->value; // sum加上根的值
t=t->ch[1]; // 递归进右儿子
}
else t=t->ch[0]; // 否则递归进左儿子
}
}
void insert(long x)
{
insert(root, x);
}
void erase(long _value)
{
erase(root, _value);
}
long size()
{
return root->size;
}
long long sum()
{
return root->sum;
}
};
long nBrick, nNeed;
long h[MAXN];
void init()
{
freopen("砖块.txt","r",stdin);
scanf("%ld%ld", &nBrick, &nNeed);
for (long i=0;i<nBrick;++i)
scanf("%ld",&h[i]);
}
void work()
{
treap*Treap=new treap;
long long ans=LONG_LONG_MAX;
for (long i=0;i<nBrick;++i)
{
Treap->insert(h[i]);
if (i>=nNeed)
Treap->erase(h[i-nNeed]);
if (i+1>=nNeed)
{
long long leftsum;
long mid;
Treap->calckth(nNeed>>1,mid,leftsum);
long long rightsum=Treap->sum()-leftsum-mid;
long long leftsize=nNeed>>1;
long long rightsize=nNeed-leftsize-1;
long long curcost=(leftsize*mid-leftsum)+(rightsum-rightsize*mid);
ans=min(ans,curcost);
}
}
printf("%lld\n",ans);
}
int main()
{
init();
work();
}