BZOJ1112: [POI2008]砖块Klo

传送门: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
",ans);
110 }
111 int main()
112 {
113     init();
114     solve();
115 } 
View Code
原文地址:https://www.cnblogs.com/HQHQ/p/5630045.html