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 }