码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ4378 : [POI2015]Logistyka

时间:2016-03-13 06:16:30      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

对于每个询问,设不小于$s$的个数为$cnt$,小于$s$的和为$sum$。

那么如果可以进行$s$轮,当且仅当$sum\geq (c-cnt)\times s$。

权值线段树维护,时间复杂度$O(m\log m)$。

证明:

如果$cnt\geq c$,那么显然可以每次取$c$个。

否则如果$sum\geq (c-cnt)\times s$,那么小于$s$的个数必然不小于$c$,可以每次取最大的$c$个来完成。

当$sum<(c-cnt)\times s$时,那么无论怎么取,都是做不到$s$轮的。

 

#include<cstdio>
#include<algorithm>
const int N=1000010,M=2100000;
int n,m,i,x,y,a[N],b[N],cb,op[N][3],v[M],cnt;long long s[M],sum;
inline void read(int&a){char c;while(!(((c=getchar())>=‘0‘)&&(c<=‘9‘)));a=c-‘0‘;while(((c=getchar())>=‘0‘)&&(c<=‘9‘))(a*=10)+=c-‘0‘;}
inline int lower(int x){
  int l=1,r=cb,mid,t=cb+1;
  while(l<=r)if(b[mid=(l+r)>>1]>=x)r=(t=mid)-1;else l=mid+1;
  return t;
}
inline void ins(int c,int V,int S){
  if(!c)return;
  int a=1,b=cb,x=1,mid;
  while(1){
    v[x]+=V,s[x]+=S;
    if(a==b)return;
    mid=(a+b)>>1,x<<=1;
    if(c<=mid)b=mid;else a=mid+1,x++;
  }
}
inline void ask(int c){
  int a=1,b=cb,x=1,mid;
  if(c>cb){cnt=0,sum=s[1];return;}
  cnt=v[1],sum=0;
  while(a<b){
    mid=(a+b)>>1,x<<=1;
    if(c<=mid)b=mid;else cnt-=v[x],sum+=s[x],a=mid+1,x++;
  }
}
int main(){
  read(n),read(m);
  for(i=1;i<=m;i++){
    char ch;
    while((ch=getchar())!=‘U‘&&ch!=‘Z‘);
    op[i][0]=ch,read(op[i][1]),read(op[i][2]);
    if(ch==‘U‘)b[++cb]=op[i][2];
  }
  std::sort(b+1,b+cb+1);
  for(i=1;i<=m;i++){
    x=op[i][1],y=op[i][2];
    if(op[i][0]==‘U‘){
      ins(a[x],-1,-b[a[x]]);
      a[x]=lower(y);
      ins(a[x],1,y);
    }else{
      ask(lower(y));
      puts(sum>=1LL*(x-cnt)*y?"TAK":"NIE");
    }
  }
  return 0;
}

  

BZOJ4378 : [POI2015]Logistyka

标签:

原文地址:http://www.cnblogs.com/clrs97/p/5271136.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!