CF 813E 分块暴力

来源:互联网 发布:blufftitler网络模板 编辑:程序博客网 时间:2024/05/16 08:29

传送门

题意: n 个士兵站一排,第i个士兵的种类是 ai ,取一些士兵可以组成军队,一支军队要满足每种士兵的个数不大于给定的 k ,处理 q 个查询,查询区间 [L,R] 之间的士兵组成的军队的最大 size 。强制在线。

做法:考虑先把所有的士兵选中,显然这样会有士兵多出来,考虑士兵 i 多出来的条件,其实就是从这个士兵往前数 k+1 个同类型的士兵,这第 k+1 个士兵如果在区间内,那士兵i显然就要删去了。于是我们预处理出每个士兵往前数 k+1 个同类型士兵的位置 p[i] ,那查询就变成了查询一个区间 [L,R] 内小于 L 的个数,这个只要分块一下,很快就写完了。不过我看到很多人写的线段树,但是既然 AC 了就不怎么想想了。

代码:

#include <bits/stdc++.h>using namespace std;int n, k, q, B;int a[105000];int p[105000];vector<int>g[105000];vector<int>buck[1050];int main(){    scanf("%d%d", &n, &k);    B=sqrt(n);    for(int i=1;i<=n;i++)scanf("%d", &a[i]);    for(int i=1;i<=n;i++){        g[a[i]].push_back(i);        int ed=g[a[i]].size();        if(ed>=k+1){            p[i]=g[a[i]][ed-k-1];        }        else p[i]=0;        buck[(i-1)/B+1].push_back(p[i]);    }    for(int i=1;i<=n/B;i++)sort(buck[i].begin(), buck[i].end());    scanf("%d", &q);    int last=0, x, y;    for(int i=1;i<=q;i++){        scanf("%d%d", &x, &y);        x=(x+last)%n+1;        y=(y+last)%n+1;        if(x>y)swap(x, y);        last=0;        int l=x, r=y;        while(l<=r){            if(l%B!=1)last+=(p[l++]<x);            else if(r%B!=0)last+=(p[r--]<x);            else {                int bp=(l-1)/B+1;                last+=lower_bound(buck[bp].begin(), buck[bp].end(), x)-buck[bp].begin();                l+=B;            }        }        printf("%d\n", last);    }}