P5070 [Ynoi Easy Round 2015] 即便看不到未来 做题记录

P5070 [Ynoi Easy Round 2015] 即便看不到未来

Description

对于一个序列 \(A\),将其去重排序,得到序列 \(B\)

  • 对于一个二元组 \((l,r) \ (l\leq r)\),称其长度为 \(r-l+1\)

  • 对于一个二元组 \((l,r)\),满足对于任意的 \(l<i\leq r\) 的整数 \(i\),都有 \(B_i=B_{i-1}+1\),则称 \((l,r)\) 是一个值域连续段。

  • 对于一个二元组 \((l,r)\),满足其是一个值域连续段,且 \((l-1,r),(l,r+1)\) 都不是,则称 \((l,r)\) 是一个极长值域连续段。

给定序列 \(A\)\(Q\) 次询问。每次询问给出 \(L,R\),输出 \(A[L,R]\) 中长度分别为 \(1,2,3,\cdots,10\) 的极长值域连续段个数。

\(1\leq n,Q,A_i\leq 10^6\)

Solution

首先将询问全部离线,挂在右端点上。考虑扫描线,我们推进右端点 \(r\),维护 \([i,r]\) 的答案。

接下来就要考虑右端点从 \(r-1\) 推进到 \(r\),对答案的贡献是什么。也就是加入 \(A_r\) 这个数字,会对这些值域连续段造成什么影响。

\(lst_x\)\(A[1,r-1]\)\(x\) 这个数字最后一次出现的位置。插入 \(A_r\) 后,只有 \(A[lst_{A_r},r]\) 这一部分的值域有变化,也就只需要维护这一部分的答案。

首先题目要求的连续段长度比较小,我们只需要考虑 \([A_r-k,A_r+k]\) 中的数字。

我们把这些数字 \(x\) 和它们的 \(lst_x\) 放入数组 \(pos\) 中,按照 \(lst\) 从大到小排序。当然,要满足 \(lst_x>lst_{A_r}\)

遍历 \(pos\)。每遍历到一个 \(pos_i\),我们就维护出新的 \(vl,vr\)表示目前包含 \(A_r\) 这个数字的极长值域连续段是什么。

对于区间 \([pos_{i+1}+1,pos_i]\)\((vl,A_r-1)\)\((A_r+1,vr)\) 这两个连续段被 \(A_r\) 接起来,变为新的极长连续段 \((vl,vr)\)

我们再维护出 \(c_{i,j}\),表示 \(A[i,r]\) 中长度为 \(j\) 的极长连续段的数量。我们需要支持区间加,单点查,对于每一个长度分别用一棵树状数组维护即可。

还有一个细节:\(k\) 具体取多少?

首先对于 \(A_r\),其所在的连续段内的数字一定都在 \([A_r-9,A_r+9]\) 内,那么 \(k\) 至少要取 \(9\)

如果一个极长连续段为 \((A_r-10,A_r-1)\) 或者 \((A_r+1,A_r+10)\),加入 \(A_r\) 后,我们需要把它们的贡献删去。那么 \(k\) 至少要取 \(10\)

但是还不够。我们需要删去长度 恰好\(10\) 的值域连续段,长度大于 \(10\) 的连续段一定在前面的 \(r'\) 中被删去了。所以我们的 \(k\) 需要取到 \(11\),来判断这些连续段长度是否恰好为 \(10\)

时间复杂度为 \(O(nk \log n)\),可以通过。

int n,m,Q,a[N],lst[N],ans[N][13];
bool vis[N];

struct Query{
	int x,id;
};
vector<Query> q[N];

struct Fenwick{
	int tr[N];
	
	void Update(int x,int v){
		for(;x<=n;x+=x&-x) tr[x]+=v;
	}
	
	void Update(int l,int r,int v){
		Update(l,v);
		Update(r+1,-v);
	}
	
	int Ask(int x){
		int res=0;
		for(;x;x-=x&-x) res+=tr[x];
		return res;
	}
}Bit[12];

struct Node{
	int x,p;
	bool operator<(const Node& tmp)const{
		return p>tmp.p;
	}
};
vector<Node> s;

signed main(){
	read(n),read(Q);
	for(int i=1;i<=n;i++){
		read(a[i]);
		Ckmax(m,a[i]);
	}
	for(int i=1;i<=Q;i++){
		int l,r;
		read(l),read(r);
		q[r].push_back({l,i});
	}
	for(int i=1;i<=n;i++){
		s.clear();
		s.push_back({a[i],i});
		int VL=max(1,a[i]-11),VR=min(m,a[i]+11);
		for(int j=VL;j<=VR;j++){
			vis[j]=0;
			if(lst[j]>lst[a[i]])
				s.push_back({j,lst[j]});
		}
		s.push_back({a[i],lst[a[i]]});
		sort(s.begin(),s.end());
		vis[a[i]]=1;
		int L=a[i],R=a[i];
		for(int j=0;j<(signed)s.size()-1;j++){
			vis[s[j].x]=1;
			while(L>VL&&vis[L-1]) L--;
			while(R<VR&&vis[R+1]) R++;
			Bit[a[i]-L].Update(s[j+1].p+1,s[j].p,-1);
			Bit[R-a[i]].Update(s[j+1].p+1,s[j].p,-1);
			if(R-L+1<=10) Bit[R-L+1].Update(s[j+1].p+1,s[j].p,1);
		}
		for(Query j:q[i])
			for(int k=1;k<=10;k++)
				ans[j.id][k]=Bit[k].Ask(j.x);
		lst[a[i]]=i;
	}
	for(int i=1;i<=Q;i++){
		for(int j=1;j<=10;j++) putchar(ans[i][j]%10+'0');
		puts("");
	}
    return 0;
}

posted @ 2025-03-21 20:33  XP3301_Pipi  阅读(52)  评论(0)    收藏  举报
Title