1. 程式人生 > >noi.ac day6t3 color

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; }