noi.ac day6t3 color

传送门

分析

将询问离线,枚举右端点。新加入一个右端点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\n",ans[i]);
    return 0;
}
posted @ 2018-10-20 14:07  水题收割者  阅读(286)  评论(0编辑  收藏  举报