NC15430. 区间的值域连续段
描述
输入描述
第一行两个数n,m,表示序列的长度和查询的次数
之后一行n个数表示这个序列
之后m行每行两个数l,r表示查询的区间
输出描述
对于每次询问,输出一个长度为10的字符串,第i个字符表示长度为i的极长连续段个数mod 10的结果
示例1
输入:
5 5 1 2 4 5 6 1 5 1 2 3 4 3 5 4 5
输出:
0110000000 0100000000 0100000000 0010000000 0100000000
示例2
输入:
8 9 2 3 3 3 3 6 6 6 1 8 2 3 4 5 6 8 1 2 3 4 5 6 3 8 5 5
输出:
1100000000 1000000000 1000000000 1000000000 0100000000 1000000000 2000000000 2000000000 1000000000
C++11(clang++ 3.9) 解法, 执行用时: 569ms, 内存消耗: 23924K, 提交时间: 2018-04-02 08:50:16
#include<bits/stdc++.h> #define MAXN 1000050 using namespace std; int N,M; char ans[MAXN][15]; int A[MAXN],pos[MAXN]; struct Query{ int l,r,id; bool operator < (const Query &rtm) const{ return r<rtm.r; } }Q[MAXN]; struct BIT{ int a[11][MAXN],n; #define Lowbit(x) (x&(-x)) void Modify(int k,int p,int v){ for(;p<=n;p+=Lowbit(p)) a[k][p]+=v; } int Query(int k,int p,int ret=0){ for(;p;p-=Lowbit(p)) ret+=a[k][p]; return ret; } }DT; int main(){ scanf("%d%d",&N,&M); DT.n=1000000; for(int i=1;i<=N;i++) scanf("%d",&A[i]); for(int i=1;i<=M;i++) Q[i].id=i,scanf("%d%d",&Q[i].l,&Q[i].r); sort(Q+1,Q+M+1); for(int i=1,j=1;i<=N&&j<=M;i++){ int last=pos[A[i]],cur=i,ll=0,rr=0,pre; while(cur>last&&(ll<=10||rr<=10)){ pre=cur; cur=last; if(ll<=10) cur=max(cur,pos[max(A[i]-ll-1,0)]); if(rr<=10) cur=max(cur,pos[min(A[i]+rr+1,1000000)]); if(ll&&ll<=10) DT.Modify(ll,cur+1,-1),DT.Modify(ll,pre+1,1); if(rr&&rr<=10) DT.Modify(rr,cur+1,-1),DT.Modify(rr,pre+1,1); if(ll+rr+1<=10) DT.Modify(ll+rr+1,cur+1,1),DT.Modify(ll+rr+1,pre+1,-1); while(ll<=10&&A[i]-ll-1>=1&&pos[A[i]-ll-1]>=cur) ++ll; while(rr<=10&&A[i]+rr+1<=1000000&&pos[A[i]+rr+1]>=cur) ++rr; } for(pos[A[i]]=i;j<=M&&Q[j].r==i;j++) for(int k=1;k<=10;k++) ans[Q[j].id][k]='0'+DT.Query(k,Q[j].l)%10; } for(int i=1;i<=M;i++) puts(ans[i]+1); return 0; }