[题解] LuoguP4168 [Violet]蒲公英

这个题原来是黑题的说

传送门

来写点清(fei)新(chang)一(du)点(liu)的分块题吧...

一句话题意:求区间众数,强制在线。

好像还有在线莫队的做法......不会 Orz

众数这玩意儿不怎么好合并,所以考虑暴力分块。

设每块的大小为\(t\),我们维护三个东西

  • \(cc[i][j]\)表示前\(i\)个块中,元素\(j\)出现了多少次(当然要离散化辣~~)
  • \(ansv[i][j]\)\(i\)个块到第\(j\)个块内的众数
  • \(ansc[i][j]\)\(i\)个块到第\(j\)个块内众数的出现次数

考虑怎么算这三个东西,\(cc\)的话\(O(n/t)\)的扫一遍所有的块,然后每次\(O(t)\)遍历块中元素就好了,复杂度为\(O(n/t^2)\)

\(ansv[i][j]\)\(ansc[i][j]\),枚举\(i\),然后在从左到右枚举\(j\)的时候遍历第\(j\)个块内的所有元素,随便开个桶算一下,复杂度\(O((n/t)^2\times t)=O(n^2/t)\)

于是预处理的复杂度就是\(O(n^2/t)\)

考虑查询区间\([l,r]\)的答案,假设第\(bl\)块到第\(br\)块被区间\([l,r]\)完全包含,刚开始的答案就是\(ansc[bl][br]\),然后枚举边角块的元素,维护个桶,更新答案即可。

因为\(n,m\)同阶,这里就用\(n\)好了,回答的总复杂度是\(O(2tn)\)

这样总复杂度就是\(n^2/t+2tn\),考虑\(t\)的取值。

\(f(x)=n^2/x+2nx\),求导得到\(f'(x)=2n-n^2x^{-2}\),当\(f'(x)=0\)时,解得\(x=(n/2)^{1/2}\)

\(t=(n/2)^{1/2}\)的时候就能得到一个较优的复杂度,大概是\(O(n^{\frac{3}{2}})\)

\(Code\)

#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;++i)
#define per(i,a,n) for (int i=n-1;i>=a;--i)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
typedef double db;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> VI;

const int N=4e4+10;
struct node {
    int v,x,id;
}a[N];
int n,m,tn,tb,tot;

int bel[N],cc[300][N],ansv[300][300],ansc[300][300];
int lb[300],rb[300];
void init() {
    tn=(int)(pow(n/2.0,0.5)+0.5);
    rep(i,1,n+1) {
        bel[i]=(i-1)/tn+1,tb=bel[i];
        lb[bel[i]]=lb[bel[i]]==0?i:lb[bel[i]];
        rb[bel[i]]=i;
    }
    rep(i,1,tb+1) rep(j,lb[i],rb[i]+1) cc[i][a[j].x]++;
    rep(i,1,tb+1) rep(j,1,tot+1) cc[i][j]+=cc[i-1][j];
    rep(i,1,tb+1) {
        static int cnt[N];
        int mxc=0,mxv=0;
        rep(j,i,tb+1) {
            rep(k,lb[j],rb[j]+1) {
                ++cnt[a[k].x];
                if(cnt[a[k].x]>mxc||(cnt[a[k].x]==mxc&&a[k].v<mxv))
                    mxv=a[k].v,mxc=cnt[a[k].x];
            }
            ansv[i][j]=mxv,ansc[i][j]=mxc;
        }
        rep(j,i,tb+1) rep(k,lb[j],rb[j]+1) --cnt[a[k].x];
    }
}

#define getcc(l,r,k) (cc[r][k]-cc[l-1][k])

int query(int l,int r) {
    int bbl=bel[l],bbr=bel[r];
    int l0=1,r0=0,l1=1,r1=0;
    if(lb[bbl]!=l) l0=l,r0=rb[bbl],++bbl;
    if(rb[bbr]!=r) l1=lb[bbr],r1=r,--bbr;
    int ans1=ansv[bbl][bbr],ans2=ansc[bbl][bbr];
    static int cnt[N];
    rep(i,l0,r0+1) {
        ++cnt[a[i].x];
        int tmpc=cnt[a[i].x]+getcc(bbl,bbr,a[i].x);
        if(tmpc>ans2||(tmpc==ans2&&a[i].v<ans1))
            ans1=a[i].v,ans2=tmpc;
    }
    rep(i,l1,r1+1) {
        ++cnt[a[i].x];
        int tmpc=cnt[a[i].x]+getcc(bbl,bbr,a[i].x);
        if(tmpc>ans2||(tmpc==ans2&&a[i].v<ans1))
            ans1=a[i].v,ans2=tmpc;
    }
    rep(i,l0,r0+1) --cnt[a[i].x];
    rep(i,l1,r1+1) --cnt[a[i].x];
    return ans1;
}

int main() {
#ifdef LOCAL
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    scanf("%d%d",&n,&m);
    rep(i,1,n+1) {
        scanf("%d",&a[i].v);
        a[i].id=i;
    }
    sort(a+1,a+n+1,[](node a,node b) {
        return a.v<b.v;
    });
    rep(i,1,n+1) a[i].x=a[i].v==a[i-1].v?a[i-1].x:++tot;
    sort(a+1,a+n+1,[](node a,node b) {return a.id<b.id;});
    init();
    int lstans=0; while(m--) {
        int l,r; scanf("%d%d",&l,&r);
        l=(l+lstans-1)%n+1,r=(r+lstans-1)%n+1;
        if(l>r) swap(l,r);
        printf("%d\n",lstans=query(l,r));
    }
    return 0;
}

感觉跑的还挺快的qwq

猜你喜欢

转载自www.cnblogs.com/wxq1229/p/12389635.html