2024.04.04 分块补题

2024/4/4 分块补题

P3203 [HNOI2010] 弹飞绵羊

分块跳跳跳,核心是每次跳出当前块,用 \(to[i]\) 表示跳到的位置。

#include <bits/stdc++.h>
using namespace std;
#define ld long double
template <typename T>
inline T read(){
    T x=0;char ch=getchar();bool fl=false;
    while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return fl?-x:x;
}
#define read() read<int>()
const int maxn = 2e5 + 10;
int be[maxn],L[maxn],R[maxn],cnt,B;
int n,m,a[maxn];
int to[maxn],f[maxn];
inline int query(int x){
    int res=0;
    while(x<=n){
        res+=f[x];x=to[x];
    }
    return res;
}
int main(){
    n=read();B=sqrt(n);
    for(int i=1;i<=n;i++){
        a[i]=read();
        be[i]=(i-1)/B+1;
        if(!L[be[i]])L[be[i]]=i,cnt++;
        R[be[i]]=i;
    }
    for(int i=n;i>=1;i--){
        if(i+a[i]>R[be[i]]){
            to[i]=i+a[i];
            f[i]=1;
        }
        else to[i]=to[i+a[i]],f[i]=f[i+a[i]]+1;
    }
    m=read();
    while(m--){
        int op=read(),pos=read()+1;
        if(op==1)printf("%d\n",query(pos));
        else {
            int x=read();a[pos]=x;
            for(int i=pos;i>=L[be[pos]];i--){
                if(i+a[i]>R[be[i]]){
                    to[i]=i+a[i];
                    f[i]=1;
                }
                else to[i]=to[i+a[i]],f[i]=f[i+a[i]]+1;
            }
        }
    }
    return 0;
}

P4168 [Violet] 蒲公英

\(m\) 次询问,每次询问区间 \([L,R]\) 的众数,强制在线。

处理出整块 \(f_{i,j}\) 的众数是谁。

对于边角块出现的数,强行计数,用前缀和来处理整块的该数出现的次数。

#include <bits/stdc++.h>
using namespace std;
#define ld long double
template <typename T>
inline T read(){
    T x=0;char ch=getchar();bool fl=false;
    while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return fl?-x:x;
}
#define read() read<int>()
const int maxn = 40000 + 10;
const int maxm = 200 + 10;
int be[maxn],L[maxn],R[maxn],B,tot,cnt[maxn];
int n,m,a[maxn],tmp[maxn],mp[maxn];
int mx[maxm][maxm],f[maxm][maxn];
inline int query(int l,int r){
    if(be[l]==be[r]){
        for(int i=l;i<=r;i++)cnt[a[i]]=0;
        for(int i=l;i<=r;i++)cnt[a[i]]++;
        int maxx=0,res=0;
        for(int i=l;i<=r;i++){
            if(maxx<cnt[a[i]])maxx=cnt[a[i]],res=a[i];
            else if(maxx==cnt[a[i]])res=min(res,a[i]);
        }
        return mp[res];
    }
    int res1=mx[be[l]+1][be[r]-1],maxx1=f[be[r]-1][res1]-f[be[l]][res1];
    int res2=0,maxx2=0;
    for(int i=l;i<=R[be[l]];i++)cnt[a[i]]=0;
    for(int i=L[be[r]];i<=r;i++)cnt[a[i]]=0;
    for(int i=l;i<=R[be[l]];i++){
        cnt[a[i]]++;
        if(a[i]==res1)maxx1++;
        int temp=cnt[a[i]]+f[be[r]-1][a[i]]-f[be[l]][a[i]];
        if(maxx2<temp)maxx2=temp,res2=a[i];
        else if(maxx2==temp)res2=min(res2,a[i]);
    }
    for(int i=L[be[r]];i<=r;i++){
        cnt[a[i]]++;
        if(a[i]==res1)maxx1++;
        int temp=cnt[a[i]]+f[be[r]-1][a[i]]-f[be[l]][a[i]];
        if(maxx2<temp)maxx2=temp,res2=a[i];
        else if(maxx2==temp)res2=min(res2,a[i]);
    }
    //cerr<<maxx1<<" "<<maxx2<<endl;//
    //cerr<<res1<<" "<<res2<<endl;//
    if(maxx1>maxx2)return mp[res1];
    else if(maxx1==maxx2)return min(mp[res1],mp[res2]);
    else return mp[res2];
}
int main(){
    n=read();m=read();B=sqrt(n);
    for(int i=1;i<=n;i++)a[i]=read(),tmp[i]=a[i];
    sort(tmp+1,tmp+1+n);
    tot=unique(tmp+1,tmp+1+n)-(tmp+1);
    for(int i=1;i<=n;i++){
        be[i]=(i-1)/B+1;
        if(!L[be[i]])L[be[i]]=i;
        R[be[i]]=i;
        int x=lower_bound(tmp+1,tmp+1+tot,a[i])-tmp;
        mp[x]=a[i];a[i]=x;
    }
    for(int i=1;i<=be[n];i++){
        for(int j=L[i];j<=R[i];j++)f[i][a[j]]++;
        for(int j=1;j<=tot;j++)f[i][j]+=f[i-1][j];
    }
    for(int i=1;i<=be[n];i++){
        memset(cnt,0,sizeof cnt);
        int maxx=0,res=0;
        for(int j=i;j<=be[n];j++){
            for(int k=L[j];k<=R[j];k++){
                cnt[a[k]]++;
                if(cnt[a[k]]>maxx)maxx=cnt[a[k]],res=a[k];
                else if(cnt[a[k]]==maxx)res=min(res,a[k]);
            }
            mx[i][j]=res;
        }
    }
    int x=0;
    while(m--){
        int l0=read(),r0=read();
        int l=(l0+x-1)%n+1,r=(r0+x-1)%n+1;
        if(l>r)swap(l,r);
        x=query(l,r);
        printf("%d\n",x);
    }
    return 0;
}

ICPC2023 Macau C.Bladestorm

找出贪心策略就好做了,难点在于维护连边。

可以分块打 \(tag\) 维护整个块的连边情况,\(tag\)\(-1\) 表示 \(i\)\(i+k\) 连边,否则向 \(tag\) 连边,及时下放标记可以保证复杂度为 \(\text{O}(n\sqrt{n})\)

#include <bits/stdc++.h>
using namespace std;
#define ld long double
template <typename T>
inline T read(){
    T x=0;char ch=getchar();bool fl=false;
    while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return fl?-x:x;
}
#define read() read<int>()
const int maxn = 1e5 + 10;
int be[maxn],L[maxn],R[maxn],B,mx;
int to[maxn],nxt[maxn],f[maxn],tag[maxn],lstf[maxn];
int n,k,a[maxn];
inline void change(int x,int val){
    if(val>0)nxt[x]=val;
    else nxt[x]=x+k;
}
inline void rebuild(int id){
    for(int i=R[id];i>=L[id];i--){
        if(nxt[i]>R[id])to[i]=nxt[i],f[i]=1,lstf[i]=(i>=mx)?0:1;
        else to[i]=to[nxt[i]],f[i]=f[nxt[i]]+1,lstf[i]=(i>=mx)?0:lstf[nxt[i]]+1;
    }
}
inline void pushdown(int id){
    if(!tag[id])return ;
    for(int i=L[id];i<=R[id];i++)change(i,tag[id]);
    tag[id]=0;
}
inline void update(int x,int y,int val){
    if(be[x]==be[y]){
        pushdown(be[x]);
        for(int i=x;i<=y;i++)change(i,val);
        rebuild(be[x]);
        return ;
    }
    pushdown(be[x]);
    for(int i=x;i<=R[be[x]];i++)change(i,val);
    rebuild(be[x]);
    pushdown(be[y]);
    for(int i=L[be[y]];i<=y;i++)change(i,val);
    rebuild(be[y]);
    for(int i=be[x]+1;i<be[y];i++)tag[i]=val;
}
inline int query(int mx){
    int now=0,res=0;
    while(now<mx){
        if(tag[be[now]]>0)res++,now=tag[be[now]];
        else if(tag[be[now]]==-1)res++,now+=k;
        else {
            if(be[now]!=be[mx])res+=f[now],now=to[now];
            else res+=lstf[now],now=to[now];
        }
    }
    return res;
}
int main(){
    int T=read();
    while(T--){
        n=read();k=read();B=sqrt(n);mx=0;
        for(int i=1;i<=n;i++)a[i]=read(),L[i]=R[i]=0;
        for(int i=0;i<=n;i++){
            be[i]=(i-1)/B+1;
            if(!L[be[i]])L[be[i]]=i;
            R[be[i]]=i;
            nxt[i]=to[i]=n+1;
            f[i]=lstf[i]=tag[i]=0;
        }
        be[0]=0;L[0]=R[0]=0;
        set<int> S;S.insert(0);
        for(int i=1;i<=n;i++){
            mx=max(mx,a[i]);
            S.insert(a[i]);
            int lst=*(--S.lower_bound(a[i]));
            int l=max(lst,a[i]-k);
            update(l,a[i]-1,-1);
            if(lst<a[i]-k)update(lst,a[i]-k-1,a[i]);
            int ans=query(mx);
            printf("%d ",ans);
        }
        puts("");
    }
    return 0;
}
posted @ 2024-04-04 21:32  ¶凉笙  阅读(27)  评论(0编辑  收藏  举报