CF85D Sum of Medians
题意翻译
一个集合,初始为空。现有三个操作:
1.add:向集合里加入数x,保证加入前集合中没有数x;
2.del:从集合中删除数x,保证删除前集合中有x;
3.sum:询问将集合里的数从小到大排序后,求下标i模5余3的数的和。
现有n次操作,对于每个查询操作,输出答案
题解Here!
一开始感觉好不可做啊。。。
然后发现,线段树好像可以搞一搞。
线段树每个节点维护$5$个值,即区间中所有$\text{下标}\mod5$后结果相同的位置的值的和。
即:在区间$[l,r]$上维护:
$$\sum_{i=l}^rv_i[i\mod 5==0],\sum_{i=l}^rv_i[i\mod 5==1],\sum_{i=l}^rv_i[i\mod 5==2],\sum_{i=l}^rv_i[i\mod 5==3],\sum_{i=l}^rv_i[i\mod 5==4]$$
再维护区间中有多少个值$num$。
合并的时候左子树不动,右子树中所有$\text{下标}\mod5==x$的位置应该是$((i-num)\%5+5)\%5$。
至于线段树怎么动态加点。。。
其实离线一下就可以把线段树搞成静态,然后离散化一下就好。
记得开$long\ long$。
还与就是在$CF$上是不能用$\%lld$来读入、输出$long\ long$,所以还是老老实实用$cin,cout$。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define LSON rt<<1 #define RSON rt<<1|1 #define DATA(x,k) a[x].data[k] #define NUM(x) a[x].num #define LSIDE(x) a[x].l #define RSIDE(x) a[x].r #define MAXN 100010 using namespace std; int n,m=0; int lsh[MAXN]; struct Question{ int f,x; }que[MAXN]; struct Segment_Tree{ long long data[5]; int num,l,r; }a[MAXN<<2]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void pushup(int rt){ NUM(rt)=NUM(LSON)+NUM(RSON); for(int i=0;i<5;i++)DATA(rt,i)=DATA(LSON,i)+DATA(RSON,((i-NUM(LSON))%5+5)%5); } void buildtree(int l,int r,int rt){ LSIDE(rt)=l;RSIDE(rt)=r;NUM(rt)=0; if(l>=r)return; int mid=l+r>>1; buildtree(l,mid,LSON); buildtree(mid+1,r,RSON); } void update(int k,int c,long long v,int rt){ if(LSIDE(rt)==RSIDE(rt)){ DATA(rt,1)+=v; NUM(rt)+=c; return; } int mid=LSIDE(rt)+RSIDE(rt)>>1; if(k<=mid)update(k,c,v,LSON); else update(k,c,v,RSON); pushup(rt); } void work(){ for(int i=1,x;i<=n;i++){ if(que[i].f==1){ x=lower_bound(lsh+1,lsh+m+1,que[i].x)-lsh; update(x,1,que[i].x,1); } else if(que[i].f==-1){ x=lower_bound(lsh+1,lsh+m+1,que[i].x)-lsh; update(x,-1,-que[i].x,1); } else cout<<DATA(1,3)<<endl; } } void init(){ char ch[2]; n=read(); for(int i=1,x;i<=n;i++){ scanf("%s",ch); if(ch[0]=='a'){ x=read(); lsh[++m]=que[i].x=x; que[i].f=1; } else if(ch[0]=='d'){ x=read(); que[i].x=x; que[i].f=-1; } else que[i].f=0; } sort(lsh+1,lsh+m+1); m=unique(lsh+1,lsh+m+1)-lsh-1; buildtree(1,m,1); } int main(){ init(); work(); return 0; }
其实还有一种更暴力的方法:
$vector$大法好!
各种$STL$乱搞就好。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<vector> using namespace std; int n; vector<int> a; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } void work(){ char ch[2]; n=read(); for(int i=1,x;i<=n;i++){ scanf("%s",ch); if(ch[0]=='a'){ x=read(); a.insert(lower_bound(a.begin(),a.end(),x),x); } else if(ch[0]=='d'){ x=read(); a.erase(lower_bound(a.begin(),a.end(),x)); } else{ long long ans=0; for(int i=2;i<a.size();i+=5)ans+=a[i]; cout<<ans<<endl; } } } int main(){ work(); return 0; }