bzoj 1112 treap

19 篇文章 0 订阅
3 篇文章 0 订阅

枚举每一个区间,用treap维护中位数和子树和更新答案
PS:treap代码风格一变再变,从指针(太难调试+太长了)->结构体(太长了)->数组

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+10;
typedef long long ll;
const ll linf=9223372036854775807LL;
int l[N],r[N],s[N],w[N],rnd[N],K;
ll v[N],sum[N],sum1,sum2,tmp,ans=linf,h[N];
int n,m,size,root;
void update(int k)
{
    s[k]=s[l[k]]+s[r[k]]+w[k];
    sum[k]=sum[l[k]]+sum[r[k]]+w[k]*v[k];
}
void rturn(int &k) {int t=l[k];l[k]=r[t];r[t]=k;update(k);update(t);k=t;}
void lturn(int &k) {int t=r[k];r[k]=l[t];l[t]=k;update(k);update(t);k=t;}
void insert(int &k,int val)
{
    if(k==0) {k=++size;v[k]=sum[k]=val;rnd[k]=rand();s[k]=w[k]=1;return ;}
    sum[k]+=val;s[k]++;
    if(v[k]==val) w[k]++;
    else if(val>v[k]){
        insert(r[k],val);if(rnd[r[k]]<rnd[k])lturn(k);}
    else {
        insert(l[k],val);if(rnd[l[k]]<rnd[k])rturn(k);}
}
void del(int &k,int val)
{
    if(k==0) return ;
    if(v[k]==val) {
        if(w[k]>1) {w[k]--;s[k]--;sum[k]-=val;return ;}
        if(l[k]*r[k]==0) k=l[k]+r[k];
        else if(rnd[r[k]]<rnd[l[k]])lturn(k),del(k,val);
        else                        rturn(k),del(k,val);
    } 
    else if(val>v[k]) {s[k]--;sum[k]-=val;del(r[k],val);}
         else         {s[k]--;sum[k]-=val;del(l[k],val);}
}
void find(int k,int rk)
{
    if(k==0) return ;
    if(rk<=s[l[k]]) {
        sum2+=(sum[r[k]]+v[k]*w[k]);
        find(l[k],rk);
    }else if(rk>s[l[k]]+w[k]) {
        sum1+=(sum[l[k]]+v[k]*w[k]);
        find(r[k],rk-s[l[k]]-w[k]);
    }else {
        sum1+=(sum[l[k]]+(rk-s[l[k]]-1)*v[k]);
        sum2+=(sum[r[k]]+(s[l[k]]+w[k]-rk)*v[k]);
        tmp=v[k];
    }
}
void getans()
{
    sum1=sum2=0;
    find(root,m);
    ll sum=(m-1)*tmp-sum1+sum2-(K-m)*tmp;
    if(sum<ans)ans=sum;
}
int main()
{
    scanf("%d%d",&n,&K);m=((K+1)>>1);
    fo(i,1,n) scanf("%lld",&h[i]);
    for(int i=1;i<=K;i++)
        insert(root,h[i]);
    getans();
    for(int i=K+1;i<=n;i++)
    {
        del(root,h[i-K]);
        insert(root,h[i]);
        getans();
    }
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值