1.算法

尺取+树状数组(nlogn)


2.实现

对于每个i来说,维护一个[l,r].然后对于每个i维护一个区间L[i],R[i]表示这个区间最大数量为k的可行区间.这里可以用个尺取就行.求出区间了之后呢,因为离线,我们可以考虑将所有区间进行排序.然后对于每个区间来说,我们可以枚举移动的点,也就是i,然后更新这个区间的答案,因为是排序完了所以必然是互不影响的,我只要控制指针移动即可得到答案.


3.代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+50;
struct vv{
    int l,r,id;ll ans;
}vnt[N];

bool cmp1(vv a,vv b)
{
     if(a.l==b.l)   return a.r<b.r;
     else           return a.l<b.l;
}//按左端点优先,其次右端点排列.

bool cmp2(vv a,vv b)
{
    return a.id<b.id;
}//输出答案

int n,cntl[N],cntr[N],L[N],R[N],a[N],q,k;
ll c1[N],c2[N];

ll lowbit(ll x)   {  return x&(-x); }

void add(ll pos,ll val)
{
    ll x=pos;
    while(pos<=n)
    {
        c1[pos]+=val;
        c2[pos]+=(x-1)*val;
        pos+=lowbit(pos);
    }
}

ll query(ll pos)
{
    ll res=0;ll x=pos;
    while(pos)
    {
        res+=x*c1[pos]-c2[pos];
        pos-=lowbit(pos);
    }return res;
}

void init()//预处理出L,R数组.
{
    //cout<<k<<endl;
    int l=1,r=1;//设立两个指针.
    for(int i=1;i<=n;i++)
    {
        //处理l
        while(l<=n&&cntl[a[l]]+1<k) {  cntl[a[l]]++,l++; }
        //处理r
        while(r<=n&&cntr[a[r]]+1<=k) {  cntr[a[r]]++,r++; }
        r--,cntr[a[r]]--,L[i]=l,R[i]=r;
        cntl[a[i]]--,cntr[a[i]]--;
    }
}

void BUG()
{
    for(int i=1;i<=n;i++)   cout<<L[i]<<' '<<R[i]<<endl;
    /*
    5 3 2           n q k
    1 2 2 1 2

    5 5
    5 4
    6 5
    6 5
    6 4
    */
}

int main()
{
    scanf("%d%d%d",&n,&q,&k);
    for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
    for(int i=1;i<=q;i++)
        scanf("%d%d",&vnt[i].l,&vnt[i].r),vnt[i].id=i;
    sort(vnt+1,vnt+1+q,cmp1);
    init();
    //BUG();
    int l=1,r=0;
    for(int pos=1;pos<=q;pos++)//枚举区间.
    {
        //(L[i],R[i])   || (vnt[i].l,vnt[i].r)
        while(l<vnt[pos].l)   add(L[l],-1),add(R[l]+1,1),l++;
        while(r<vnt[pos].r)   add(L[++r],1),add(R[r]+1,-1);
        vnt[pos].ans=query(vnt[pos].r)-query(vnt[pos].l-1);
    }
    sort(vnt+1,vnt+1+q,cmp2);
    for(int i=1;i<=q;i++)   printf("%lld\n",vnt[i].ans);
    return 0;
}
/*
    模拟你都不会好意思打算法竞赛?
*/