考察:树状数组
思路:
操作1: 将序列的第k个数改为a 很明显的树状数组单点修改
操作2:在这个序列上,每次选出c个正数,看是否能-s次 这个操作与区间大小无关,也就是所有操作都是在整个序列上进行的.我们需要求出正数的个数,并且求出是否每次能选出c个-1.
每个操作都是a>=0,所以直接统计个数,求个数可以考虑离散化的树状数组.
每次都选出c个正数,减s个1.比较直观的想法就是求正数的和,然后>=s即为true.但数据: 正数:898989 1 1 s = 8 即可hack.
我们把正数>=s与<s的分开考虑.假设有cnt个>=s的正数,这些正数是不用考虑的.if(cnt>=c) puts("TAK");
但是如果cnt<c.我们就要看c-cnt个<s的正数.再用之前直观的想法就是if sum>=s 即为true.从感性上这个结论是正确的,但是理性上本蒟蒻也不知道如何证明
现在就是求出>=s的正数个数,与<s的正数的和.这个都可以用树状数组完成,但是需要两个.
检验cnt*s+sum>=c*s.
不管怎样都TLE了一个点,只能O2优化了
时间复杂度O(mlog2m+m*log2m)
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 typedef long long LL; 7 const int N = 3,M = 1000010; 8 int n,m,last[M]; 9 vector<LL> A; 10 LL tr[2][M];//0求<s的和,1求>=s的个数 11 char s[N]; 12 struct Query{ 13 int k,a; 14 bool ask; 15 }q[M]; 16 int get(int x) 17 { 18 return lower_bound(A.begin(),A.end(),x)-A.begin()+1; 19 } 20 int lowbit(int x) 21 { 22 return x&-x; 23 } 24 void add(int t,int k,int x) 25 { 26 for(int i=k;i<=M-10;i+=lowbit(i)) tr[t][i]+=x; 27 } 28 LL ask(int t,int x) 29 { 30 LL res = 0; 31 for(int i=x;i;i-=lowbit(i)) res+=tr[t][i]; 32 return res; 33 } 34 int main() 35 { 36 scanf("%d%d",&n,&m); 37 for(int i=1;i<=m;i++) 38 { 39 int x,y; 40 scanf("%s%d%d",s,&x,&y); 41 if(s[0]=='U') q[i].k = x,q[i].a = y,q[i].ask = 0; 42 else q[i].k = x,q[i].a = y,q[i].ask = 1; 43 A.push_back(y); 44 } 45 sort(A.begin(),A.end()); 46 A.erase(unique(A.begin(),A.end())); 47 for(int i=1;i<=m;i++) 48 if(q[i].ask)//>=s的有多少个. 49 {//if 50 int s = get(q[i].a); 51 int sz = ask(0,M-10)-ask(0,s-1); 52 LL sum = ask(1,s-1);//<s的和 53 if((LL)sz*q[i].a+sum>=(LL)q[i].k*q[i].a) puts("TAK") ; 54 else puts("NIE"); 55 }else{//将第k个数修改为a 56 int s = get(q[i].a); 57 if(last[q[i].k]) 58 {//上一个数字删去 59 int ns = get(last[q[i].k]); 60 add(0,ns,-1); add(1,ns,-last[q[i].k]); 61 } 62 last[q[i].k] = q[i].a; 63 add(0,s,1); add(1,s,q[i].a); 64 } 65 return 0; 66 }