CF813E-Army Creation【主席树】

题意:

给定 \(N\) 个数,以及 \(Q\) 个询问,每个询问给出 \(L\)\(R\),现在问在这个区间最多可以选取多少个数,使得每个数出现次数不能大于 \(K\),强制在线。

分析:

  当 \(k=1\) 时,本题就是求区间内不同的数的个数。因此,二者可以采用相同的方法来解决。
  在求区间内不同数的个数的问题中,以位置建立主席树,记录每个数上一次出现的位置,当该数再次出现时,消除前一次出现的影响,记录这一次的影响。
  本题中,用数组记录每个数最近 \(k\) 次出现的位置,当第 \(k+1\) 次出现时,把第 \(1\) 次出现的影响消除,记录下第 \(k+1\) 次的影响,以此类推。

代码:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e5+5;
struct node
{
    int val,lson,rson;
}tree[N*40];
int root[N],tol;
vector<int>ap[N];
void pushup(int t)
{
    tree[t].val=tree[tree[t].lson].val+tree[tree[t].rson].val;
}
int build(int l,int r)
{
    int cnt=++tol;
    if(l==r)
    {
        tree[cnt].val=0;
        return cnt;
    }
    int mid=(l+r)>>1;
    tree[cnt].lson=build(l,mid);
    tree[cnt].rson=build(mid+1,r);
    pushup(cnt);
    return cnt;
}
int update(int l,int r,int pos,int w,int rt)
{
    int cnt=++tol;
    tree[cnt]=tree[rt];
    if(l==r)
    {
        tree[cnt].val+=w;
        return cnt;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        tree[cnt].lson=update(l,mid,pos,w,tree[rt].lson);
    else
        tree[cnt].rson=update(mid+1,r,pos,w,tree[rt].rson);
    pushup(cnt);
    return cnt;
}
int query(int l,int r,int L,int R,int rt)
{
    if(L<=l&&r<=R)
        return tree[rt].val;
    int mid=(l+r)>>1,res=0;
    if(L<=mid)
        res+=query(l,mid,L,R,tree[rt].lson);
    if(R>mid)
        res+=query(mid+1,r,L,R,tree[rt].rson);
    return res;
}
int main()
{
    int n,k,a,q,x,y,l,r,ans=0;
    tol=0;
    scanf("%d%d",&n,&k);
    root[0]=build(1,n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a);
        ap[a].pb(i);
        if(ap[a].size()>k)
        {
            root[i]=update(1,n,ap[a][0],-1,root[i-1]);
            root[i]=update(1,n,i,1,root[i]);
            ap[a].erase(ap[a].begin());
        }
        else
            root[i]=update(1,n,i,1,root[i-1]);
    }
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d%d",&x,&y);
        l=(x+ans)%n+1;
        r=(y+ans)%n+1;
        if(l>r) swap(l,r);
        ans=query(1,n,l,r,root[r]);
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/1024-xzx/p/13205381.html