一. 题目
二. 思路
三. 代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int tfind(int l, int r, int x);
void init();
int n, m, k;
int a[N], f[N];//原数组以及预处理数组
LL ans[N];//答案数组
unordered_map<int, int> has;//某个数出现次数
signed main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++) scanf("%d", &a[i]);
init();//预处理出来f[i]:f[i]-i之间的不同数的个数等于k,且f[i]尽可能大
for(int i=1;i<=m;i++)
{
int ll, rr;
scanf("%d%d", &ll, &rr);
int l=min(ll^ans[i-1], rr^ans[i-1])+1;//解密
int r=max(ll^ans[i-1], rr^ans[i-1])+1;
if(!f[r]||f[r]<l)//表明没有这样的区间
{
puts("0");//这里是枚举所有右端点, 找所有合法情况
continue;
}
int t=tfind(1, n, l);//二分厂最小的大于等于l的f[i]
for(int j=t;j<=r;j++) ans[i]+=f[j]-l+1;//加上所有的合法左端点
printf("%lld\n", ans[i]);
}
}
int tfind(int l, int r, int x)
{
while(l<r)
{
int mid=l+r>>1;
if(f[mid]>=x) r=mid;
else l=mid+1;
}
return l;
}
void init()
{
int cnt=0;
for(int i=1, j=1;i<=n;i++)//i是右指针, j是左指针
{
if(!has[a[i]]) cnt++;//出现新数
has[a[i]]++;
while((cnt>k||has[a[j]]-1>0)&&j<i)//如果不同数的个数大于k或者当前数去掉j到i之间的不同数之间的个数不变
{
has[a[j]]--;
if(!has[a[j]]) cnt--;
j++;
}
if(cnt==k) f[i]=j;
}
}