正题
评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=P4879
题目大意
有若干种操作
- Cxy:ax−=yC\ x\ y:a_x-=yC x y:ax−=y
- Ixy:I\ x\ y:I x y:加一个(原本有的话就改变)ax=ya_x=yax=y
- Q:Q:Q:询问所以数的和
- Dx:D\ x:D x:删除第xxx个(有的才算)数。
解题思路
我们发现只有单点修改,和全部求和。所以ansansans表示全部的和,然后前三个操作就搞定了。
第四个操作维护一个分块,记录每块有的数的个数,然后找到目标在那个块,之后这个块里暴力寻找,这个操作时间负责度O(n)O(\sqrt n)O(n)
总体时间复杂度:O(nn)O(n\sqrt n)O(nn)
codecodecode
#include<cstdio>
#include<cmath>
#include<iostream>
#define ll long long
#define N 500000
#define T 1000
using namespace std;
ll n,m,a[N+10],ans,no[N+10],x,y,t;
ll L[T],R[T],num[T],pos[N+10];
char c;
int main()
{scanf("%lld%lld",&n,&m);t=sqrt(N);for(ll i=1;i<=N;i++){pos[i]=(i-1)/t+1;if(i>n)no[i]=1;}for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);num[pos[i]]++;ans+=a[i];}for(ll i=1;i<=m;i++){cin>>c;if(c=='Q')printf("%lld\n",ans);else if(c=='I'){scanf("%lld%lld",&x,&y);ans-=a[x];a[x]=y;ans+=y;n=max(n,x);if(no[x]){no[x]=0;num[pos[x]]++;}}else if(c=='C'){scanf("%lld%lld",&x,&y);if(no[x]) continue;ans-=y;a[x]-=y;}else if(c=='D'){scanf("%lld",&x);ll k=1;while(x-num[k]>0)x-=num[k],k++;for(int i=(k-1)*t+1;i<=min(k*t,n);i++){if(!no[i]) --x;if(!x){num[k]--;no[i]=1;ans-=a[i];a[i]=0;break;}}}}
}