思路:
线段树+二分
先预处理每个点往后走k步的下标
线段树二叉树的每个节点用vector维护这些下标,给这些下标排个序
询问区间L,R,那么把下标小于等于R的位置都减掉,因为只要后面连续k个就够了
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define pb push_back #define ls rt<<1,l,m #define rs rt<<1|1,m+1,r #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e5+5; int a[N],now[N],nxt[N],pre[N],nxtk[N],ans=0; vector<int>vc[N<<2]; void build(int rt,int l,int r){ if(l==r){ vc[rt].pb(nxtk[l]); return ; } for(int i=l;i<=r;i++)vc[rt].pb(nxtk[i]); sort(vc[rt].begin(),vc[rt].end()); int m=(l+r)>>1; build(ls); build(rs); } void query(int L,int R,int rt,int l,int r){ if(L<=l&&r<=R){ int T=upper_bound(vc[rt].begin(),vc[rt].end(),R)-vc[rt].begin(); ans-=T; return ; } int m=(l+r)>>1; if(L<=m)query(L,R,ls); if(R>m)query(L,R,rs); } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n,k,q,l,r; cin>>n>>k; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<N;i++)now[i]=n+1; nxt[n+1]=n+1; for(int i=n;i>=1;i--){ nxt[i]=now[a[i]]; pre[now[a[i]]]=i; now[a[i]]=i; } for(int i=1;i<=n;i++){ if(i==now[a[i]]){ int t=i,cnt=0; while(t!=n+1&&cnt<k){ t=nxt[t]; cnt++; } nxtk[i]=t; } else{ nxtk[i]=nxt[nxtk[pre[i]]]; } } cout<<endl; build(1,1,n); cin>>q; while(q--){ cin>>l>>r; l+=ans; r+=ans; l=l%n+1; r=r%n+1; if(l>r)swap(l,r); ans=r-l+1; query(l,r,1,1,n); cout<<ans<<endl; } return 0; }
原文地址:https://www.cnblogs.com/widsom/p/8524911.html
时间: 2024-10-16 09:30:58