BZOJ1112: [POI2008]砖块Klo

来源:互联网 发布:怎么学淘宝运营 编辑:程序博客网 时间:2024/03/29 04:01
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1112
题目大意:N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动          作完成任务.
题解:我们看看n是106于是我们可以枚举k,是O(n)的,那么看看时间复杂度,就需要一个logN的算法来删除一个数,加入一个数,寻找第k个数,于是平衡树即可!时间复杂度:NlogN;
   实际上刚开始想的是二分次数+二分长度,想想应该也是可行的,只不过在答案验证上,可以自己想想,反正我不知道!
  1 #include<iostream>  2 #include<cstring>  3 #include<cstdio>  4 #include<algorithm>  5 #include<cmath>  6 #define maxn 100005  7 #define ll long long   8 #define linf 9223372036854775807LL  9 using namespace std; 10 int n,k,root,mid,mmid,sz; 11 ll tmp; 12 ll sum1,sum2,ans; 13 int a[maxn]; 14 int ls[maxn],rs[maxn],size[maxn],w[maxn],rnd[maxn]; 15 ll sum[maxn],v[maxn]; 16 int read() 17 { 18     int x=0; char ch; bool bo=0; 19     while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') bo=1; 20     while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); 21     if (bo) return -x; return x; 22 } 23 void updata(int k) 24 { 25     sum[k]=sum[ls[k]]+sum[rs[k]]+w[k]*v[k]; 26     size[k]=size[ls[k]]+size[rs[k]]+w[k]; 27 } 28 void rturn(int &k) 29 { 30     int t=ls[k]; ls[k]=rs[t]; rs[t]=k; updata(k); updata(t); k=t; return; 31 } 32 void lturn(int &k) 33 { 34     int t=rs[k]; rs[k]=ls[t]; ls[t]=k; updata(k); updata(t); k=t; return; 35 } 36 void ins(int &k,int val) 37 { 38     if (!k)  39     { 40         k=++sz; size[k]=w[k]=1; v[k]=sum[k]=val; rnd[k]=rand(); return ; 41     } 42     size[k]++; sum[k]+=val; 43     if (val==v[k]) w[k]++; 44     if (v[k]>val){ins(ls[k],val); if (rnd[ls[k]]>rnd[k]) rturn(k);} 45     if (v[k]<val){ins(rs[k],val); if (rnd[rs[k]]>rnd[k]) lturn(k);} 46     updata(k); 47 } 48 void del(int &k,int val) 49 { 50     if (!k) return ; 51     if (v[k]==val) 52     { 53         if (w[k]) 54         { 55             w[k]--; size[k]--; sum[k]-=val; return ; 56         } 57         if (ls[k]*rs[k]==0) k=ls[k]+rs[k]; 58         else 59         { 60             if (rnd[ls[k]]>rnd[rs[k]]) {rturn(k); del(k,val);} 61             else {lturn(k); del(k,val);} 62         } 63     } 64     else if (v[k]>val) {sum[k]-=val; size[k]--; del(ls[k],val);} 65     else {sum[k]-=val; size[k]--; del(rs[k],val);} 66 } 67 void init() 68 { 69     n=read(); k=read(); mmid=k/2+1; ans=linf; 70     for(int i=1; i<=n; i++) a[i]=read(); 71 } 72 void find(int k,int rank) 73 { 74     if(!k)return;     75     if(rank>size[ls[k]]&&rank<=size[ls[k]]+w[k]) 76     { 77         sum1+=(sum[ls[k]]+(rank-size[ls[k]]-1)*v[k]); 78         sum2+=(sum[rs[k]]+(size[ls[k]]+w[k]-rank)*v[k]); 79         tmp=v[k]; 80     } 81     else if(rank<=size[ls[k]]) 82     { 83         sum2+=(v[k]*w[k]+sum[rs[k]]); 84         find(ls[k],rank); 85     } 86     else  87     { 88         sum1+=(v[k]*w[k]+sum[ls[k]]); 89         find(rs[k],rank-size[ls[k]]-w[k]); 90     } 91 }   92 void getans() 93 { 94     sum1=sum2=0; 95     find(root,mmid); 96     ll sum=(mmid-1)*tmp-sum1+sum2-(k-mmid)*tmp; 97     if(sum<ans)ans=sum; 98 } 99 void solve()100 {101     root=0;102     for (int i=1; i<=k; i++) ins(root,a[i]); 103     getans();104     for (int i=k+1; i<=n; i++)105     {106         del(root,a[i-k]); ins(root,a[i]);107         getans();108     }109     printf("%lld\n",ans);110 }111 int main()112 {113     init();114     solve();115 } 
View Code

 

0 0
原创粉丝点击