BZOJ4378: [POI2015]Logistyka
n<=1e6个数字,开始都是0,m<=1e6个操作:1、把第x个数修改成y;2、询问:对序列中的数字进行c次操作,每次选s个正数把他们-1,问能否进行。
一个数字Ai,如果Ai>=s,那它可以被选中s次;如果Ai<s,那就Ai次。设k个数字大于等于s,小于s的数字的和是sum,只需要:sum<=(c-k)*s就一定可以完成操作。正确性证明:如果sum<(c-k)*s,那根本不够操作,必要;如果sum>=(c-k)*s,每次选最大的那几个数-1即可。
因此只需要维护大于等于某个数字的个数和小于某个数字的数的和,这些可以把询问离线后离散化,树状数组维护即可。
ps:离散化后加个unique效果更佳!!
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 //#include<assert.h> 5 #include<math.h> 6 #include<algorithm> 7 //#include<iostream> 8 using namespace std; 9 10 int n,m; 11 #define maxn 1000011 12 #define LL long long 13 struct BIT 14 { 15 LL a[maxn];int n; 16 void clear(int n) {memset(a,0,sizeof(a));this->n=n;} 17 void add(int x,LL v) {for (;x<=n;x+=x&-x) a[x]+=v;} 18 LL query(int x) {LL ans=0;for (;x;x-=x&-x) ans+=a[x];return ans;} 19 }tv,tc; 20 int lisan[maxn],num[maxn]; 21 struct Doo 22 { 23 char s[3];int x,y; 24 }doo[maxn]; 25 bool isdigit(char c) {return c>='0' && c<='9';} 26 int qread() 27 { 28 char c;int s=0;while (!isdigit(c=getchar())); 29 do s=s*10+c-'0'; while (isdigit(c=getchar()));return s; 30 } 31 int main() 32 { 33 scanf("%d%d",&n,&m); 34 for (int i=1;i<=m;i++) 35 { 36 scanf("%s",doo[i].s);doo[i].x=qread(),doo[i].y=qread(); 37 lisan[i]=doo[i].y; 38 } 39 sort(lisan+1,lisan+1+m); 40 tv.clear(m); tc.clear(m); 41 memset(num,0,sizeof(num)); 42 for (int i=1;i<=m;i++) 43 { 44 if (doo[i].s[0]=='U') 45 { 46 if (num[doo[i].x]>0) 47 { 48 int pos=lower_bound(lisan+1,lisan+1+m,num[doo[i].x])-lisan; 49 tv.add(pos,-num[doo[i].x]); 50 tc.add(m-pos+1,-1); 51 } 52 num[doo[i].x]=doo[i].y; 53 int pos=lower_bound(lisan+1,lisan+1+m,doo[i].y)-lisan; 54 tv.add(pos,doo[i].y); 55 tc.add(m-pos+1,1); 56 } 57 else 58 { 59 int pos=lower_bound(lisan+1,lisan+1+m,doo[i].y)-lisan; 60 printf(tv.query(pos-1)>=(doo[i].x-tc.query(m-pos+1))*1ll*doo[i].y?"TAK\n":"NIE\n"); 61 } 62 } 63 return 0; 64 }