既然这道题目要我们维护出现在%5=3位置上面的值,那么我现在想想是不是这个线段区间上面只可能有5种状态的线段树出现。
那么我就只用维护这五种状态,最后只用看3状态上面的数字之和为多少就ok了。。
当然还是要来一个离线处理,因为你现在必须知道对于这一整组数据而言要建立多大的一颗线段树。
View Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<string.h> 5 #define LL __int64 6 using std::unique; 7 using std::sort; 8 const int N = 100005; 9 LL sum[N<<2][5]; 10 int cover[N<<2],num[N],qnum[N]; 11 char order[N][5]; 12 void build(int t,int l,int r) 13 { 14 cover[t]=0; 15 memset(sum[t],0,sizeof(sum[t])); 16 if(l==r)return ; 17 int m=(l+r)>>1; 18 build(t<<1,l,m); 19 build(t<<1|1,m+1,r); 20 } 21 void PushUp(int t) 22 { 23 int t1=t<<1,t2=t1|1; 24 cover[t]=cover[t1]+cover[t2]; 25 for(int i=0;i<5;i++)sum[t][i]=sum[t1][i]; 26 for(int i=0;i<5;i++)sum[t][(i+cover[t1])%5]+=sum[t2][i]; 27 } 28 void update(int t,int l,int r,int p,int val) 29 { 30 if(l==r) 31 { 32 cover[t]=val; 33 sum[t][1]=(val?num[l]:0); 34 return ; 35 } 36 int m=(l+r)>>1; 37 if(p<=m)update(t<<1,l,m,p,val); 38 else update(t<<1|1,m+1,r,p,val); 39 PushUp(t); 40 } 41 int Fin(int k,int len) 42 { 43 int l=0,r=len; 44 while(l<r) 45 { 46 int m=(l+r)>>1; 47 if(num[m]==k)return m; 48 if(num[m]>k)r=m-1; 49 else l=m+1; 50 } 51 return l; 52 } 53 int main() 54 { 55 int n; 56 while(~scanf("%d",&n)) 57 { 58 int topn=0; 59 for(int i=0;i<n;i++) 60 { 61 scanf("%s",order[i]); 62 if(order[i][0]!='s') 63 { 64 scanf("%d",&qnum[i]); 65 num[topn++]=qnum[i]; 66 } 67 } 68 sort(num,num+topn); 69 topn=unique(num,num+topn)-num-1; 70 build(1,0,topn); 71 for(int i=0;i<n;i++) 72 { 73 if(order[i][0]=='a') 74 { 75 int l=Fin(qnum[i],topn); 76 update(1,0,topn,l,1); 77 } 78 if(order[i][0]=='d') 79 { 80 int l=Fin(qnum[i],topn); 81 update(1,0,topn,l,0); 82 } 83 if(order[i][0]=='s') 84 printf("%I64d\n",sum[1][3]); 85 } 86 } 87 return 0; 88 }