Loj #6723. 「CodePlus #7」教科书般的亵渎 线段树+树状数组

退役选手只能来补数据结构的题解。

我们设当前情况下伤害 \(d\) 会触发 \(cnt[d]\) 次,那么 \(\displaystyle ans=\frac{\displaystyle \sum_{i=L}^{R}cnt[i]}{R-L+1}\)

如果我们能求出来维护好的 \(cnt\) 数组的话,用树状数组做前缀和就能询问了。

维护的方法很简单,我们建一颗线段树,对于伤害 \(d\) ,如果当前场上存在血量在 \(1\) ~ \(d\) ,\(d+1\) ~ \(2d\) 。。。各至少一只,但不存在血量在 \(kd+1\) ~ \((k+1)d\) 的怪,那么就把 \(d\) 放到响度按书上相应的区间。

当新来一个怪,沿着线段树把先相应的 \(d\) 取出来更新就行了。

时间复杂度是 调和级数套上线段树套上set(或者其他的可以维护插入删除的数据结构), \(O(nlog^3n)\)

考场上sb了,刚考完就就会了QAQ

可以尝试看代码理解。

#include<iostream>
#include<cstdio>
#include<queue>
#define LL long long
using namespace std;
int n,m,top,now;
LL ans;
const int N=100010,M=1000010;
int L[N],R[N],zhan[N];
inline int read()
{
    int res = 0; char ch = getchar(); bool XX = false;
    for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    return XX ? -res : res;
}
struct SZSZ
{
	LL tr[N];
	int lowbit(int x){return x&(-x);}
	void add(int pos,int v)
	{
		for(;pos<=n;pos+=lowbit(pos))tr[pos]+=v;
	}
	LL ask(int pos)
	{
		int res=0;
		for(;pos;pos-=lowbit(pos))res+=tr[pos];
		return res;
	}
}Ans,tong;
struct dui 
{
	priority_queue<int>p, q;
	void upd() 
	{
		while (!q.empty() && !p.empty() && q.top() == p.top())q.pop(), p.pop();
	}
	void Insert(int x) {q.push(x); upd();}
	void Delete(int x) {p.push(x); upd();}
	int top() {upd(); return q.top();}
	int size() {return q.size() - p.size();}
};
namespace XDS
{
	#define lson (k<<1)
	#define rson ((k<<1)|1)
	dui q[N<<2];
	void Insert(int k,int l,int r,int x,int y,int v)
	{
		if(x<=l&&r<=y)
		{
			q[k].Insert(v);
			return;
		}
		int mid=(l+r)>>1;
		if(x<=mid)Insert(lson,l,mid,x,y,v);
		if(mid+1<=y)Insert(rson,mid+1,r,x,y,v);
	}
	void updata(int k,int l,int r,int pos)
	{
		while(q[k].size())zhan[++top]=q[k].top(),q[k].Delete(zhan[top]);
		if(l==r)return;
		int mid=(l+r)>>1;
		if(pos<=mid)updata(lson,l,mid,pos);
		else updata(rson,mid+1,r,pos);
	}
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i)Ans.add(i,1),XDS::Insert(1,1,n,1,i,i),L[i]=1,R[i]=i;
	while(m--)
	{
		int opt=read();
		if(opt==1)
		{
			int h=read();if(now==n)continue;
			top=0;XDS::updata(1,1,n,h);
			tong.add(h,1);
			for(int i=1,v,l,r;i<=top;++i)
			{
				v=zhan[i];
				l=L[v];r=R[v];
				while(1)
				{
					if(tong.ask(r)-tong.ask(l-1))Ans.add(v,1);
					else {L[v]=l;R[v]=r;XDS::Insert(1,1,n,l,r,v);break;}
					l=r+1;r=min(n,l+v-1);
					if(l==n+1){++now;break;}
				}
			}
		}
		else
		{
			int l=read(),r=read();
			printf("%lld\n",Ans.ask(r)-Ans.ask(l-1));
		}
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/wljss/p/13370415.html