2012 ACM/ICPC 成都赛区网络赛A题解题报告

这道题是网络原题,题目地址:http://www.codeforces.com/contest/85/problem/D

 

读完题目你可以很快知道这是一道线段树的题目,题目意思是:3种操作。插入一个数,删除一个数,都保证序列有序。以及求和,其中求和是将下标%5==3的所有数求和。

 

思路是:用5棵线段树维护,s[0]表示%5==1的下标,其他依次类推 cnt,记录子树的元素个数。

想要得到该区间内所有模5等3所有元素的和,左孩子可以求到,两个孩子相互独立,所以求右孩子需要知道(左子树含有 )多少个元素,因为这样分开求的时候,我们才知道 求右孩子时应该求下标模5等几()的所有元素的和。

假如我们 求 i == 3 时(表示 %5 == 4),对于左子树我们直接求就可以 ,但是对于右子树,我们要知道在 i== 3 的情况下 ,右子树的 元素的下标应该是 %5 ==几?所以就是(当前位置减去左子树的元素个数)%5

 ans[rt][i]=ans[ls][i]+ans[rs][(i-sum[ls]%5+5)%5];这样敲代码就是一件比较轻松的事情了。

 说明:
    unique(num,mun+n)返回的是num去重后的尾地址,并不是真正把重复的元素删除,而
    是,该函数把重复的元素移到后面去了,依然保存到了原数组中,函数返回去重后最
    后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排
    一下序。
   
    lower_bound(num,num+n,x)返回的是num前n个数中出现的第一个“>=x”的数的位置。
   
    注意:这两个函数用之前都要排序。
   

    代码:

 
#include <iostream>
 #include <cstdio>
 #include <cstring>
 #include <cmath>
 #include <algorithm>
 
 using namespace std;
 
 #define mid (l+r)>>1
 #define ls rt<<1
 #define rs rt<<1|1
 #define lson l,m,rt<<1
 #define rson m+1,r,rt<<1|1
 
 #define MAXN 100010
 int sum[MAXN<<2]; //区间的元素个数
 __int64 ans[MAXN<<2][5];//分别表示mod5
 int key[MAXN];//离散化用
 int x[MAXN];
 
 char op[MAXN][10];
 
 void pushup(int rt)
 {
     for(int i=0;i<5;i++)
     {
         ans[rt][i]=ans[ls][i]+ans[rs][(i-sum[ls]%5+5)%5];
     }
 }
 
 void build(int l,int r,int rt)
 {
     sum[rt]=0;
     memset(ans[rt],0,sizeof(ans[rt]));
     if(l==r)   
         return;
     int m = mid;
     build(lson);  
     build(rson);
 }
 
 int flag;//判断用
 void update(int p,int l,int r,int rt)
 {
     sum[rt]+=2*flag-1;
     if (l==r)    
     {
         ans[rt][1]=flag*key[p];//叶子节点的值mod5肯定为1
         return ;
     }
     int m=mid;
     if (p<= m)       
         update(p,lson);
     else    
         update(p,rson);
     pushup(rt);     
 }
 
 int main()
 {
     int n,tot=0;
     while(scanf("%d",&n) != EOF)
     {
         tot=0;
         for(int i=0;i<n;i++)
         {    
             scanf("%s",op[i]);
             if(op[i][0]=='a' || op[i][0]=='d')
             {    
                 scanf("%d",&x[i]);
                 key[tot++]=x[i];
             }
         }
         sort(key,key+tot);
         tot = unique(key,key+tot) - key;
         build(1,tot,1);
         for(int i=0;i<n;i++)
         {
             int pos = lower_bound(key,key+tot,x[i]) - key;
             if(op[i][0] == 's')
                 printf("%I64d\n",ans[1][3]);
             else
             {
                 if(op[i][0]=='a')
                     flag=1;
                 else
                     flag=0;
                 update(pos,1,tot,1);
             }
         }
     }
     return 0;
 }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值