求助分块5pts

P4168 [Violet] 蒲公英

______l______ @ 2022-09-25 15:12:00

按第一篇题解的思路去写的 具体思路在代码注释里 除了18其它全WA

#include<bits/stdc++.h>
//#pragma GCC optimize(3,"Ofast","inline")
//#define int long long
using namespace std;
const int N=1e5+10,sqrtN=sqrt(N);int n,m,q;
int a[N],x[N],ans[sqrtN][sqrtN],s[sqrtN][N],p[N];
int l[sqrtN],r[sqrtN],t,num;
/*
ans[i][j]:块i~块j的众数
s[i][j]:前i块中x[j]出现的次数(j是离散化编号)
*/
inline int time10(int x)
{return(x<<3)+(x<<1);}
inline int read(){//快读
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        if(ch==-1)exit(0);
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
        x=time10(x)+(ch^48),ch=getchar();
    return x*f;
}
inline void write(int x){//快写
    if(x<0)putchar('-'),x=-x;
    if(x<10){putchar(x+48);return;}
    write(x/10);putchar(x%10+48);
}
inline int name(int k){//查k的离散化编号
    return lower_bound(x+1,x+m+1,k)-x;
}
inline void init(int k){//分块
    p[k]=k/t+1;//块的编号
    if(p[k]!=p[k-1])//和上一个数不是同一个块
        r[p[k-1]]=k-1,l[p[k]]=k;//这两个数是块的边界
    if(k==n)r[p[k]]=k;//最后一个数
}int cnt[N],cut[N];
inline int ask(int ql,int qr,int x){//查询块ql~块qr中x出现的次数
    int k=name(x);
    return s[qr][k]-s[ql-1][k];
}//前缀和
inline int query(int ql,int qr){//询问O(sqrt n)
    memset(cnt,0,sizeof cnt);//清零
    if(p[qr]-p[ql]<=1){//中间没有完整块
        int as=INT_MAX,ar=0;//记录
        for(int i=ql;i<=qr;i++){//暴力求答案
            int k=name(a[i]);
            cnt[k]++;
            if(cnt[k]>ar||(cnt[k]==ar&&a[i]<as))
                ar=cnt[k],as=a[i];
        }return as;
    }if(l[p[ql]]==ql&&r[p[qr]]==qr)//边界的两数
        return ans[p[ql]][p[qr]];
    int ans1=ans[p[ql]+1][p[qr]-1];
    int cnt1=ask(p[ql]+1,p[qr]-1,ans1);
    //答案1:中间整块的众数
    int ans2=INT_MAX,cnt2=0;
    //答案2:整块边的数+这个数在中间整块中出现次数
    for(int i=ql;i<=r[p[ql]];i++){//ql所在块
        int k=name(a[i]);cnt[k]++;
        if(cnt[k]==1)//第一次记录
            cnt[k]+=ask(p[ql]+1,p[qr]-1,a[i]);//将中间的也加上
        if(cnt[k]>cnt2||(cnt[k]==cnt2&&a[i]<ans2))//赋值
            cnt2=cnt[k],ans2=a[i];
    }
    for(int i=l[p[qr]];i<=qr;i++){//qr所在块
        int k=name(a[i]);cnt[k]++;//同上
        if(cnt[k]==1)
            cnt[k]+=ask(p[ql]+1,p[qr]-1,a[i]);
        if(cnt[k]>cnt2||(cnt[k]==cnt2&&a[i]<ans2))
            cnt2=cnt[k],ans2=a[i];
    }//cout<<ans1<<":"<<cnt1<<"/"<<ans2<<":"<<cnt2<<"——";
    return(cnt1>cnt2||(cnt1==cnt2&&ans1<ans2))?ans1:ans2;//选择答案
}
signed main(){
    n=read(),q=read();t=sqrt(n);num=n/t+1;
    for(int i=1;i<=n;i++)//输入
        a[i]=read(),x[i]=a[i],init(i);
    sort(x+1,x+n+1);
    m=unique(x+1,x+n+1)-x;
    /*离散化*/
    int ks=INT_MAX,kr=0;
    /*O(n)*/
    for(int i=1;i<=num;i++)//枚举整块
        for(int j=l[i];j<=r[i];j++){//预处理s数组
            int xh=name(a[j]);
            cnt[xh]++;
            if(cnt[xh]>kr||(cnt[xh]==kr&&a[j]<ks))
                kr=cnt[xh],ks=a[j];//无视就好
            s[i][xh]=cnt[xh];
        }
    int ts=INT_MAX,tr=0;
    /*O(n sqrt n)*/
    for(int i=1;i<=num;i++){//枚举<起点>
        memset(cut,0,sizeof cut);//归零
        ts=INT_MAX,tr=0;//记录答案
        for(int j=i;j<=num;j++){//枚举块&自己
            for(int k=l[j];k<=r[j];k++){//
                int xh=name(a[k]);
                cut[xh]++;
                if(cut[xh]>tr||(cut[xh]==tr&&a[k]<ts))
                    tr=cut[xh],ts=a[k];
            }ans[i][j]=ts;//保存答案
//          cout<<"第"<<l[i]<<"到第"<<r[j]<<":"<<ans[i][j]<<"\n";
        }
    }int answer=0;//上一次询问答案
    while(q--){
        int sl=read(),sr=read();
        int ql=((sl+answer-1)%n)+1;
        int qr=((sr+answer-1)%n)+1;
//      cout<<ql<<"~"<<qr<<":";
        if(ql>qr)swap(ql,qr);
        write(answer=query(ql,qr)),
        putchar('\n');//输出
    }fclose(stdin);
    fclose(stdout);
    return 0;
}

蒟蒻求助!!!


|