题意:
给出一个有序集合,3种操作。插入一个数,删除一个数,都保证序列有序。以及求和
其中求和是将下标%5==3的所有数求和,这道题是2012年成都网络预赛的题目,一开始只知道用线段树,但不知从何下手,
因为要求的不是连续区间的元素之和,而是满足%5==3的所有数求和,当时我就迷茫了,之后搜了网上的题解,基本上弄懂了。
思路:线段树求解,不过与以往的不同这个是多棵的线段树,每个节点下有五个元素集,每个是当前树所有下标%5==3的元素的和,这样就可以去求满足条件的元素和了。
1 #include2 #include 3 using namespace std; 4 const int N=100005; 5 struct { 6 int l,r,cnt; 7 __int64 s[5]; 8 }tree[3*N]; 9 int a[N],b[N];10 bool vis[N];11 void build(int l,int r,int i){12 tree[i].l=l;13 tree[i].r=r;14 tree[i].cnt=0;15 memset(tree[i].s,0,sizeof(tree[i].s));16 if(l >1;18 build(l,mid,i<<1);19 build(mid+1,r,i<<1|1);20 }21 }22 void add(int p,int i,int flag){23 tree[i].cnt+=flag*2-1;24 if(tree[i].l==p && tree[i].r==p){25 tree[i].s[0]=flag*a[p];26 return;27 }28 int mid=(tree[i].l+tree[i].r)>>1;29 if(p<=mid) add(p,i<<1,flag);30 else add(p,i<<1|1,flag);31 for(int j=0;j<5;j++)//自底向上更新父节点信息 32 tree[i].s[j]=tree[i<<1].s[j]+tree[i<<1|1].s[(j-tree[i<<1].cnt%5+5)%5];33 }34 int main()35 {36 int n,i,k,p;37 char cmd[5];38 while(~scanf("%d",&n)){39 memset(b,0,sizeof(b));40 memset(vis,0,sizeof(vis));41 for(k=i=0;i