您的位置:首页 > 其它

[bzoj4378] [POI2015]Logistyka

2016-03-23 14:24 405 查看
  离线+树状数组。。

  对于某个询问(S次,每次选出C个数),数列中每个数最多被减S次,只要判断(C- (数列中>=S的数个数))*S是否小于等于(数列中<S的数的和)就好了。

  或者说。。把数列中>=S的数都变成S后,求一下总和是否大于等于S*C。。。

  因为数字可能很大所以离线后hash一发。

  网上的奇怪证明都是什么鬼。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1000233;
struct zs{
int id,v;
}b[maxn];int cnt;
struct ask{
bool id;int x,y;
}q[maxn];
int mp[maxn],t[maxn],c[maxn];
ll sm[maxn],sum;
int i,j,k,n,m,num;

int ra;char rx;
inline int read(){
rx=getchar(),ra=0;
while(rx<'0'||rx>'9')rx=getchar();
while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
}
inline void add(int x){
//  printf("add %d\n",x);
for(int i=x;i<=cnt;i+=i&-i)t[i]++,sm[i]+=c[x];
}
inline void del(int x){
for(int i=x;i<=cnt;i+=i&-i)t[i]--,sm[i]-=c[x];
}
inline void query(int x,int &num,ll &sum){
num=sum=0;
for(int i=x;i;i-=i&-i)num+=t[i],sum+=sm[i];
}

bool cmp(zs a,zs b){return a.v<b.v;}
int main(){
n=read(),m=read();char id;
for(i=1;i<=m;i++){
for(id=getchar();id<'A'||id>'Z';id=getchar());
q[i].id=id=='U';
if(id=='U')q[i].x=read(),q[i].y=read();
else q[i].x=read(),q[i].y=read();
b[i].v=q[i].y,b[i].id=i;
}
sort(b+1,b+1+m,cmp);
for(i=1;i<=m;i++){
if(b[i].v!=b[i-1].v||i==1)c[++cnt]=b[i].v;
q[b[i].id].y=cnt;
}
int n1=0;
for(i=1;i<=m;i++){
//      printf("%d  %d %d\n",q[i].id,q[i].x,q[i].y);
if(q[i].id){
//  all-=c[mp[q[i].x]],all+=c[q[i].y];
if(mp[q[i].x])del(mp[q[i].x]);else n1++;
add(q[i].y),mp[q[i].x]=q[i].y;
}else{
query(q[i].y,num,sum);num=n1-num;//printf("number>=%d:%d    rest:%lld\n",c[q[i].y],num,sum);
if(sum>=(ll)c[q[i].y]*(q[i].x-num))puts("TAK");else puts("NIE");
}
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: