luogu P4879 ycz的妹子

背景:

水題都要找半天錯。

題目傳送門:

https://www.luogu.org/problem/P4879

題意:

基本操作就是,在第xx位置改值;將第opop個有值的位置的值刪除;詢問整段的和。

思路:

除了刪除,樹狀數組都可以優秀的解決。
考慮記錄當前這個位置是否有值,在對這個統計一個前綴和,那麼找第opop個位置就可以二分了。
理論時間複雜度:Θ(nlog2)\Theta(n\log^2 長度)
當然你用線段樹在樹中二分地去找也行,時間複雜度:Θ(nlog)\Theta(n\log 長度)
然而樹狀數組不光代碼優秀,而且實測飛快,下面的代碼169ms\text{169ms}(沒有卡常),基本碾壓大多數線段樹。

代碼:

#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));
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章