UOJ Logo kczno1的博客

博客

bzoj 由乃运椰子

2017-05-10 18:19:18 By kczno1

简要题意:
区间众数 强制在线 空间<n根号

区间众数的做法很普通
就是分根号块 预处理两块之间众数mx[i][j],以及cnt[i][j]表示前i块中权值j出现次数
询问时要么众数是块间原本的众数 否则一定在多出来的里面出现过 时间n根号
由于cnt[i][j] 空间n根号

如何优化空间呢

特判掉出现次数<k的权值 这样cnt[i][j]中j就<=n/k 空间就变成n根号/k了

怎么特判呢 就是再用个l[k][i]表示出现次数=k时,右端点为i,第一次可以的那个左端点(也就是最大的那个)

我k取了3 (由于初始ans为清0,导致第一次就异或,wa了很久很久)

#include<cstdio>
#include<algorithm>
#include<string.h>
using std::sort;
using std::swap;

#define us unsigned short
#define gc getchar()
void read(us &x)
{
    char ch;
    while((ch=gc)<'0');
    for(x=ch-'0';(ch=gc)>='0';)x=x*10+ch-'0';
}
void read(int &x)
{
    char ch;
    while((ch=gc)<'0');
    for(x=ch-'0';(ch=gc)>='0';)x=x*10+ch-'0';
}

void chmax(us &x,us y)
{
    if(x<y)x=y;
}

#define B(i) ((i-1)/len)
const int K=240,N=60000,U=N/4+5;
us kl[K],kr[K];
us cnt[K][U],mx[K][K];
us n,m,i,j,l,len,k;
us a[N+5],top;bool del[N+5];
us now[U],st[N/K*2+10],stt,nowmx;
us dr[N+5],dl[N+5];
us l_2[N+5],l_3[N+5];//l_i[r]= 当右端点=[1,r]时,达到i需要的最大左端点 

struct item
{
    int a;us id;
    bool operator <(const item &i)const
    {
        return a<i.a;
    }
}q[N+5];
void mark(us l,us r)
{
    if(l>r)swap(l,r);
    del[l]=del[r]=1;chmax(l_2[r],l);
}
void mark(us a,us b,us c)
{
if(a>b)swap(a,b);
if(b>c)
{swap(b,c);
if(a>b)swap(a,b);
}
    del[a]=del[b]=del[c]=1;
    chmax(l_3[c],a);
    chmax(l_2[c],b);
    chmax(l_2[b],a);
}
void check(us i)
{
    if(i==1||(q[i].a!=q[i-1].a)) 
    {    
        del[q[i].id]=1; 
        --top;
    }else
    if(i==2||(q[i].a!=q[i-2].a)) 
    {
        mark(q[i].id,q[i-1].id); 
        --top;
    }else
    if(i==3||(q[i].a!=q[i-3].a))
    {
        mark(q[i].id,q[i-1].id,q[i-2].id);
        --top;
    }
}
void lisan()
{
    for(i=1;i<=n;++i){read(q[i].a);q[i].id=i;}
    sort(q+1,q+n+1);
    top=a[q[1].id]=0;
    for(i=2;i<=n;++i)
    {
     if(q[i].a!=q[i-1].a) 
     {
       check(i-1);++top;
     }
     a[q[i].id]=top;  
    }
    check(n);
}

void write(us x)
{
    putchar('-');
    for(;x;x/=10)st[++stt]=x%10;
    for(;stt;--stt)putchar('0'+st[stt]);
    putchar('\n');
}

us ql,qr,L,R;

int main()
{   freopen("1.in","r",stdin);freopen("2.out","w",stdout);
    read(n);read(m);
    lisan();

    us t=0;
    for(i=1;i<=n;++i)
    {
        if(del[i])dr[i]=t;
        else a[dr[i]=++t]=a[i];
    }
    dl[n+1]=++t;
    for(i=n;i;--i)
    {
        if(del[i])dl[i]=t;
        else dl[i]=--t;
    }
    t=dr[n];
    for(i=1;i<=n;++i) {chmax(l_2[i],l_2[i-1]);chmax(l_3[i],l_3[i-1]);}

    if(!t)
    {
        while(m--)
        {
            read(ql);read(qr);
                ql^=nowmx;qr^=nowmx;
            nowmx=(ql<=l_3[qr])?3:((ql<=l_2[qr])?2:1);
            write(nowmx);
        }
        return 0;
    }

    for(len=1;B(t)>=K||len<t/len;++len);
    kl[0]=1;
    for(i=len+1;i<=t;i+=len) {kr[B(i)-1]=i-1;kl[B(i)]=i;} 
    kr[k=B(t)]=t;

    for(i=0;i<=k;++i)
    {
        nowmx=0;
        for(j=i;j<=k;++j)
        {
          for(l=kl[j];l<=kr[j];++l)
          if(++now[a[l]]>nowmx)nowmx=now[a[l]];
          mx[i][j]=nowmx;
          if(!i)memcpy(cnt[j],now,(top+1)*2);
        }
        memset(now,0,(top+1)*2);
    }

    nowmx=0;
    while(m--)
    {
        read(ql);read(qr);
        ql^=nowmx;qr^=nowmx;
        L=B(dl[ql]);R=B(dr[qr]);
        if(L>=R) 
        {
            for(i=dl[ql];i<=dr[qr];++i)
            if(++now[a[i]]==1) st[++stt]=a[i];
            nowmx=0;
            for(;stt;--stt) 
            {
              if(now[st[stt]]>nowmx)nowmx=now[st[stt]];
              now[st[stt]]=0;
            }
        }
        else
        {
            for(i=dl[ql];i<=kr[L];++i)
            if(++now[a[i]]==1) st[++stt]=a[i];
            for(i=kl[R];i<=dr[qr];++i)
            if(++now[a[i]]==1) st[++stt]=a[i];
            nowmx=mx[L+1][R-1];
            for(;stt;--stt) 
            {
              us &x=now[st[stt]];
              x+=cnt[R-1][st[stt]]-cnt[L][st[stt]];
              if(x>nowmx)nowmx=x;
              x=0;
            }
        }
        if(nowmx<3)
        {
         if(ql<=l_3[qr])nowmx=3;
         else
         if(nowmx<2)
         {
           if(ql<=l_2[qr])nowmx=2;
           else
           if(nowmx<1)nowmx=1; 
         }
        }
        write(nowmx);
    }
}

评论

OldDriverTree
这套YNOI的题好妙啊 都是好题啊 思路很棒啊

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。