题意:你有n次操作,每次可以往集合里插入元素,删除元素,然后如果是求和操作的话,是求升序排序的情况下,pos%5==3的位置的数之和。
思路:因为要开权值线段树数很大,所以先把操作离线把要用到的数都离散化了,然后线段树维护的是区间数的个数num和区间位置%5==i的位置的数之和sum[i],我们最后查询的时候要的是根节点的sum[3],这题的关键就是这个pushup里的更新sum【i】值。
for(int i=0;i<=4;i++)
sum[rt][i]=sum[ls][i]+sum[rs][((i-num[ls])%5+5)%5];
因为求根节点的sum[3]的时候说不定用的是右儿子的sum[0,1,2,3,4]里的哪个,所有对节点都要维护sum[0~4],然后sum[rt][i]要直接加上左儿子的sum[ls][i]是毋庸置疑的,关键是要找到rs节点对应区间里的数放到rt节点区间里时位置%5==i的位置的数之和是多少假设这个位置是pos,那么有(ls.num+pos)%5==i,我们要的就是满足条件的pos位置的数之和,然后有
同余式相加:若a≡b(mod m),c≡d(mod m),则a+c≡b+d(mod m); 减法也成立
同余式相乘:若a≡b(mod m),c≡d(mod m),则ac≡bd(mod m)。
所有可以得到pos同余(i-ls.num) 在mod5情况下,那么就有pos%5==(i-ls.num)%5,所以要的就是右儿子的sum[(i-ls.num)%5]。由于pos%5==(i-ls.num)%5这个是数学上相等,到了c++里面可以就不一定相等了因为数学里(-20)%11==2,但是c++里(-20)%11==-9,所以写代码的时候还要考虑(i-ls.num)%5为负数的情况,那么((i-ls.num)%5+5)%5就可以避免负数的情况了,所以应该是加sum[((i-num[ls])%5+5)%5]。
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define ll __int64
#define fuck(x) cout<<#x<<" "<<x<<endl;
const int maxn=1e5+20;
int d[4][2]={1,0,-1,0,0,1,0,-1};
int num[maxn<<2],n,vcnt;
ll sum[maxn<<2][5],lsh[maxn];
struct node
{
char op[10];
ll val;
}q[maxn];
inline int getid(ll x)
{
return lower_bound(lsh+1,lsh+vcnt+1,x)-lsh;
}
void pushup(int rt)
{
num[rt]=num[ls]+num[rs];
for(int i=0;i<=4;i++)
sum[rt][i]=sum[ls][i]+sum[rs][((i-num[ls])%5+5)%5];
}
void update(int rt,int L,int R,int pos,int val)
{
if(L==R)
{
if(val==1)
{
num[rt]=1;
sum[rt][1]=1LL*lsh[pos];
}
else
{
num[rt]=0;
sum[rt][1]=0LL;
}
return ;
}
int mid=(L+R)>>1;
if(pos<=mid)
update(ls,L,mid,pos,val);
else
update(rs,mid+1,R,pos,val);
pushup(rt);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
vcnt=0;
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%s",q[i].op);
if(q[i].op[0]=='a'||q[i].op[0]=='d')
scanf("%I64d",&(q[i].val)),lsh[++vcnt]=q[i].val;
}
sort(lsh+1,lsh+vcnt+1);
vcnt=unique(lsh+1,lsh+vcnt+1)-lsh-1;
for(int i=1;i<=n;i++)
if(q[i].op[0]=='a')
update(1,1,vcnt,getid(q[i].val),1);
else
if(q[i].op[0]=='d')
update(1,1,vcnt,getid(q[i].val),0);
else
printf("%I64d
",sum[1][3]);
}
return 0;
}