bzoj1112 [POI2008]砖块Klo

题目链接

一眼中位数,treap可做

怎么维护呢?

枚举O(n)个区间,区间和可以直接维护对吧,然后找区间中排名为(k+1)/2的数(中位数)。

问题是怎么找小于中位数的数的和。

这个可以在treap中维护子树和然后在找中位数时统计即可。

有了区间和,那么大于中位数的数的和也能求,然后更新答案即可。

手残没旋转T了几发。。。

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<string>
  7 #include<cmath>
  8 #include<ctime>
  9 #include<queue>
 10 #include<stack>
 11 #include<map>
 12 #include<set>
 13 #define rre(i,r,l) for(int i=(r);i>=(l);i--)
 14 #define re(i,l,r) for(int i=(l);i<=(r);i++)
 15 #define Clear(a,b) memset(a,b,sizeof(a))
 16 #define inout(x) printf("%d",(x))
 17 #define douin(x) scanf("%lf",&x)
 18 #define strin(x) scanf("%s",(x))
 19 #define LLin(x) scanf("%lld",&x)
 20 #define op operator
 21 #define CSC main
 22 typedef unsigned long long ULL;
 23 typedef const int cint;
 24 typedef long long LL;
 25 using namespace std;
 26 void inin(int &ret)
 27 {
 28     ret=0;int f=0;char ch=getchar();
 29     while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
 30     while(ch>='0'&&ch<='9')ret*=10,ret+=ch-'0',ch=getchar();
 31     ret=f?-ret:ret;
 32 }
 33 int a[100010],ch[100010][2],c[100010],s[100010],r[100010],ed,root,tot1;
 34 LL w[100010],tot,ans,sum[100010];
 35 LL sum1;
 36 void maintain(int k)
 37 {
 38     if(k)s[k]=c[k]+s[ch[k][0]]+s[ch[k][1]],
 39     sum[k]=sum[ch[k][0]]+sum[ch[k][1]]+(LL)c[k]*w[k];
 40 }
 41 void rotate(int &k,int d)
 42 {
 43     int p=ch[k][d^1];
 44     ch[k][d^1]=ch[p][d];
 45     ch[p][d]=k;
 46     maintain(k);
 47     maintain(p);k=p;
 48 }
 49 void add(int &k,const LL &x)
 50 {
 51     if(!k)
 52     {
 53         k=++ed,s[k]=c[k]=1,ch[k][0]=ch[k][1]=0,w[k]=sum[k]=x,r[k]=rand();
 54         return ;
 55     }
 56     s[k]++,sum[k]+=x;
 57     if(w[k]==x){c[k]++;return ;}
 58     int d=x>w[k];
 59     add(ch[k][d],x);
 60     if(r[ch[k][d]]<r[k])rotate(k,d^1);
 61 }
 62 bool del(int &k,const LL &x)
 63 {
 64     if(!k)return 0;
 65     if(w[k]==x)
 66     {
 67         if(c[k]>1){c[k]--;s[k]--;sum[k]-=x;return 1;}
 68         if(!ch[k][0]){k=ch[k][1];return 1;}
 69         if(!ch[k][1]){k=ch[k][0];return 1;}
 70         if(r[ch[k][0]]<r[ch[k][1]])rotate(k,1);
 71         else rotate(k,0);
 72         return del(k,x);
 73     }
 74     int d=x>w[k];
 75     if(del(ch[k][d],x)){s[k]--;sum[k]-=x;return 1;}
 76     else return 0;
 77 }
 78 int findwei(int k,const int &x)
 79 {
 80     int pp=(ch[k][0]?s[ch[k][0]]:0);
 81     if(x>pp&&x<=pp+c[k]){sum1+=sum[ch[k][0]];tot1+=pp;return k;}
 82     if(x>pp+c[k]){sum1+=sum[ch[k][0]]+(LL)c[k]*w[k];tot1+=pp+c[k];return findwei(ch[k][1],x-pp-c[k]);}
 83     else return findwei(ch[k][0],x);
 84 }
 85 int n,k;
 86 void getans(int d)
 87 {
 88     int m=findwei(root,(k+1)>>1);
 89     LL sum2=tot-sum1-(LL)c[m]*w[m];
 90     int tot2=k-tot1-c[m];
 91     if(d)ans=(LL)tot1*w[m]-sum1+sum2-(LL)tot2*w[m];
 92     else ans=min(ans,(LL)tot1*w[m]-sum1+sum2-(LL)tot2*w[m]);
 93 }
 94 int CSC()
 95 {
 96     freopen("in.in","r",stdin);
 97     freopen("out.out","w",stdout);
 98     scanf("%d%d",&n,&k);
 99     re(i,1,n)scanf("%d",&a[i]);
100     re(i,1,k)add(root,a[i]),tot+=a[i];
101     tot1=sum1=0;
102     getans(1);
103     re(j,1,n-k)
104     {
105         del(root,a[j]);
106         add(root,a[j+k]);
107         tot-=a[j],tot+=a[j+k];
108         tot1=sum1=0;
109         getans(0);
110     }
111     printf("%lld",ans);
112     return 0;
113 }

 

posted @ 2016-01-22 13:17  HugeGun  阅读(197)  评论(0编辑  收藏  举报