线段树 || 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。

注意细节:因为H[i]的值域是0到1e6,所以我们得把它+1才能拿去当普通线段树(像主席树那样记录下标也行)的下标(否则用0去左移找儿子

时会出锅。);既然H[i]中的值都+1了,线段树的下标范围也应该相应地扩大。

代码:

 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\n",ans);
75     return 0;
76 }

By:AlenaNuna

猜你喜欢

转载自www.cnblogs.com/AlenaNuna/p/10432762.html
今日推荐