BZOJ4378 : [POI2015]Logistyka
对于每个询问,设不小于s的个数为cnt,小于s的和为sum。
那么如果可以进行s轮,当且仅当sum≥(c−cnt)×s。
权值线段树维护,时间复杂度O(mlogm)。
证明:
如果cnt≥c,那么显然可以每次取c个。
否则如果sum≥(c−cnt)×s,那么小于s的个数必然不小于c,可以每次取最大的c个来完成。
当sum<(c−cnt)×s时,那么无论怎么取,都是做不到s轮的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #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; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步