分块从入门到超时

P1886 滑动窗口 /【模板】单调队列

肥婆纳妾 @ 2019-09-09 18:11:29


#include<iostream>
#include<cstdio>
#include<math.h>
#include<climits>
using namespace std;
#define FOR(i,v,n) for(register int i=v;i<=n;++i)
#define CLEAR_ARR(a,val) memset(a,val,sizeof(a))
#define _MAX(a,b) (a>b?a:b)
#define _MIN(a,b) (a>b?b:a)

const int maxn=1e7+6;
int bsz,n,m;
int tag_min[10000],tag_max[10000],bl[maxn],v[maxn];
inline int read(){
    int x=0,w=0;char ch=0;
    while(!isdigit(ch))w|=ch=='-',ch=getchar();
    while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
void write(int x)
{
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
inline void build(){
    bsz=sqrt(n*10);
    FOR(i,0,1000)tag_max[i]=INT_MIN,tag_min[i]=INT_MAX;
    FOR(i,1,n)v[i]=read();
    FOR(i,1,n)bl[i]=(i-1)/bsz+1;
    FOR(i,1,n)tag_min[bl[i]]=_MIN(tag_min[bl[i]],v[i]),tag_max[bl[i]]=_MAX(tag_max[bl[i]],v[i]);
}
inline int ask_min(int l,int r){
    if(l<1)l=1;
    if(r<1)return 0;
    int ans=INT_MAX;
    FOR(i,l,_MIN(bl[l]*bsz,r))
        ans=_MIN(ans,v[i]);
    if(bl[l]!=bl[r])
        FOR(i,(bl[r]-1)*bsz+1,r)
            ans=_MIN(ans,v[i]);
    FOR(i,bl[l]+1,bl[r]-1)
        ans=_MIN(ans,tag_min[i]);
    return ans;
}
inline int ask_max(int l,int r){
    if(l<1)l=1;
    if(r<1)return 0;
    int ans=INT_MIN;
    FOR(i,l,_MIN(bl[l]*bsz,r))
        ans=_MAX(ans,v[i]);
    if(bl[l]!=bl[r])
        FOR(i,(bl[r]-1)*bsz+1,r)
            ans=_MAX(ans,v[i]);
    FOR(i,bl[l]+1,bl[r]-1)
        ans=_MAX(ans,tag_max[i]);
    return ans;
}
int main(){
    n=read(),m=read();
    build();
    FOR(i,m+1,n+1)
        write(ask_min(i-m,i-1)),putchar(' ');
    putchar('\n');
    FOR(i,m+1,n+1)
        write(ask_max(i-m,i-1)),putchar(' ');
    return 0;
}

by GreenDay @ 2019-09-09 18:16:48

线段树/单调队列呀

n^{1.5} $怎么过 $ n = 10^6

by 肥婆纳妾 @ 2019-09-09 18:19:49

@GreenDay 不会算复杂度,就想试一下,结果t了一个点


|