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\)。在遍历的过程中,我们维护一个 \(vl,vr\),表示目前包含 \(A_r\) 这个数字的极长值域连续段是什么。
每枚举一个 \(pos_i\),我们就维护出新的 \(vl,vr\)。对于区间 \([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;}int Ask(int l,int r){return Ask(r)-Ask(l-1);}
}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;
}