分析
将询问离线,枚举右端点。新加入一个右端点i时,假设离i第t近的同色位置为p,t+1近的是q,则当i是右端点时,(q,p]的点可以作为左端点。
注意对于一个点离它第t近的同色点可以用队列维护求得
之后用树状数组差分一下就可以了
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
struct node {
int le,ri,id;
};
node a[500010];
vector<int>q[500010];
int C[500010],d[500010],n,m,k,t,ans[500010];
int nxt[500010],fa[500010],pre[500010],ppre[500010],is[500010];
inline bool cmp(const node x,const node y){return x.ri<y.ri;}
inline int lb(int x){return x&(-x);}
inline void add(int x,int k){while(x<=n)d[x]+=k,x+=lb(x);}
inline int Q(int x){int res=0;while(x)res+=d[x],x-=lb(x);return res;}
int main(){
int i,j=1;
scanf("%d%d%d%d",&n,&m,&k,&t);
for(i=1;i<=n;i++)scanf("%d",&C[i]);
for(i=1;i<=m;i++)scanf("%d%d",&a[i].le,&a[i].ri),a[i].id=i;
sort(a+1,a+m+1,cmp);
for(i=1;i<=k;i++)q[i].push_back(0);
for(i=1;i<=n;i++){
int x=C[i],s=q[x].size();
q[x].push_back(i);
if(s>=t)add(q[x][s-t]+1,1),add(q[x][s-t+1]+1,-1);
if(s>t)add(q[x][s-t-1]+1,-1),add(q[x][s-t]+1,1);
for(j;j<=m;j++)
if(a[j].ri==i)ans[a[j].id]=Q(a[j].le);
else break;
}
for(i=1;i<=m;i++)printf("%d
",ans[i]);
return 0;
}