背景:
水題都要找半天錯。
題目傳送門:
https://www.luogu.org/problem/P4879
題意:
基本操作就是,在第位置改值;將第個有值的位置的值刪除;詢問整段的和。
思路:
除了刪除,樹狀數組都可以優秀的解決。
考慮記錄當前這個位置是否有值,在對這個統計一個前綴和,那麼找第個位置就可以二分了。
理論時間複雜度:。
當然你用線段樹在樹中二分地去找也行,時間複雜度:
然而樹狀數組不光代碼優秀,而且實測飛快,下面的代碼(沒有卡常),基本碾壓大多數線段樹。
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define lowbit(x) ((x)&(-(x)))
using namespace std;
int n,m;
LL a[500010],tr1[500010],tr2[500010];
void add(LL *tr,int x,LL y)
{
for(;x<=500000;x+=lowbit(x))
tr[x]+=y;
}
LL getsum(LL *tr,int x)
{
LL sum=0;
for(;x;x-=lowbit(x))
sum+=tr[x];
return sum;
}
int find(int x)
{
int l=1,r=500000,mid,op;
while(l<=r)
{
mid=(l+r)>>1;
int tmp=getsum(tr1,mid);
if(x<=tmp) op=mid,r=mid-1; else l=mid+1;
}
return op;
}
int main()
{
int x;
LL y;
char s[5];
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
a[i]=x;
add(tr1,i,1),add(tr2,i,x);
}
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
if(s[1]=='C')
{
scanf("%d %lld",&x,&y);
add(tr2,x,-y);
a[x]-=y;
}
else if(s[1]=='I')
{
scanf("%d %lld",&x,&y);
if(!(getsum(tr1,x)-getsum(tr1,x-1))) add(tr1,x,1); else add(tr2,x,-a[x]);
a[x]=y,add(tr2,x,a[x]);
}
else if(s[1]=='D')
{
scanf("%d",&x);
int tmp=find(x);
if(tmp!=-1) add(tr1,tmp,-1),add(tr2,tmp,-a[tmp]);
}
else if(s[1]=='Q')
{
printf("%lld\n",getsum(tr2,500000));
}
}
}