zoukankan      html  css  js  c++  java
  • 线段树 || BZOJ 1112: [POI2008]砖块Klo

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1112

    题解:

    希望有连续K柱的高度是一样的,就先把1~K的数扔进线段树(线段树的下标就是数值,不需要离散化),求一波中位数和答案作为初始答案,

    再从第K+1到N扫一遍,依次把每个数扔进线段树同时把第i-K个树弄出来扔掉,不断求中位数和更新答案就好了。

    这里求序列中所有数到中位数的距离是这样求的:线段树多维护一个sum,当前序列中小于中位数的数的个数记为cnt1,

    和为sum1,大于中位数的数的个数记为cnt2,和为sum2。于是答案就很显然是:pt(即中位数)*cnt1-sum1+sum2-pt*cnt2。

    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define ll long long
     5 #define min(a,b) ((a)<(b)?(a):(b))
     6 using namespace std;
     7 const int maxn=100000+50,maxh=1000000+50,max_h=maxh-40;
     8 int N,K,Z;
     9 ll sum[2],H[maxn],ans,pt,cnt[2];
    10 inline ll rd(){
    11     ll x=0;int f=1;char c=getchar();
    12     while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
    13     while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
    14     return f*x;
    15 }
    16 struct Tree{
    17     int l,r;
    18     ll sum,cnt;
    19 }t[maxh<<2];
    20 inline void Build(int x,int l,int r){
    21     t[x].l=l;t[x].r=r;int mid=(l+r)>>1;
    22     if(l==r)return;
    23     Build(x<<1,l,mid);Build(x<<1|1,mid+1,r);
    24     return;
    25 }
    26 inline void Update(int x,int q,int o){
    27     int l=t[x].l,r=t[x].r,mid=(l+r)>>1;
    28     if(l==r&&l==q){
    29         if(o==1){t[x].sum+=l; t[x].cnt++;}
    30             else{t[x].sum-=l; t[x].cnt--;}
    31         return;
    32     }
    33     int ls=x<<1,rs=x<<1|1;
    34     if(q<=mid)Update(ls,q,o);else Update(rs,q,o);
    35     t[x].sum=t[ls].sum+t[rs].sum;
    36     t[x].cnt=t[ls].cnt+t[rs].cnt;
    37     return;
    38 }
    39 inline int Find(int x,int z){//寻找中位数 
    40     int l=t[x].l,r=t[x].r,ls=x<<1,rs=x<<1|1;
    41     if(l==r)return l;
    42     if(t[ls].cnt>=z)return Find(ls,z);else return Find(rs,z-t[ls].cnt);
    43 }
    44 inline void Work(int x,int ql,int qr,int o){
    45     int l=t[x].l,r=t[x].r,mid=(l+r)>>1,ls=x<<1,rs=x<<1|1;
    46     if(ql<=l&&r<=qr){
    47         sum[o]+=t[x].sum;
    48         cnt[o]+=t[x].cnt;
    49         return;
    50     }
    51     if(ql<=mid)Work(ls,ql,qr,o);
    52     if(qr>mid)Work(rs,ql,qr,o);
    53     return;
    54 }
    55 int main(){
    56     N=rd();K=rd();
    57     for(int i=1;i<=N;i++){H[i]=rd();H[i]++;}
    58     Build(1,1,max_h);
    59     for(int i=1;i<=K;i++)Update(1,H[i],1);
    60     Z=(K+1)>>1;
    61     pt=Find(1,Z);//pt即为中位数 
    62     sum[0]=sum[1]=cnt[0]=cnt[1]=0;
    63     Work(1,1,pt,0);Work(1,pt,max_h,1);
    64     ans=(cnt[0]*pt-sum[0])+(sum[1]-cnt[1]*pt);
    65     for(int i=K+1;i<=N;i++){
    66         Update(1,H[i-K],2);Update(1,H[i],1);
    67         pt=Find(1,Z);
    68         sum[0]=sum[1]=cnt[0]=cnt[1]=0;
    69         Work(1,1,pt,0);Work(1,pt,max_h,1);
    70         if(ans>(cnt[0]*pt-sum[0])+(sum[1]-cnt[1]*pt)){
    71             ans=(cnt[0]*pt-sum[0])+(sum[1]-cnt[1]*pt);
    72         }
    73     }
    74     printf("%lld
    ",ans);
    75     return 0;
    76 }

    By:AlenaNuna

  • 相关阅读:
    以太坊:用 Solidity 写测试用例
    以太坊:测试合约
    以太坊:支持 Quorum 开发
    以太坊:编写外部脚本
    以太坊:使用控制台
    以太坊:调试合约
    Rancher 2.x 搭建及管理 Kubernetes 集群
    我的友情链接
    我的友情链接
    我的友情链接
  • 原文地址:https://www.cnblogs.com/AlenaNuna/p/10432762.html
Copyright © 2011-2022 走看看