bzoj4358: permu

终于又可以好好学习了?雾zzzz

 

开始写了一发KDT,做法就是把询问看成二维坐标点,然后按大小顺序插入每一个数字,包含它的区间计数器+1,否则归零

那么答案就是历史最大值

看起来很好写??(雾)

这个东西的标记。。。。呵呵呵。。。

Rose巨神告诉我要用到历史最值线段树相关打标记的方法。。。。orz了吉司机很久然而还没有写出来。。。

 

换个做法。。也是带根号的莫队

对于每个位置维护在值域中向左右的最大连续长度,每次加入一个数,通过它值域左右的数可以得到更新,然后它不需要把包含它的那连续一整段全部更新,只需要更新这一段的边界点即可

先将左端点分块,一个块中的询问按右端点排序,对于非当前块的数,因为右端点递增相当于扫一次,当前块的每次暴力算一次,然后清空即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int c[51000];
int block,st[51000];
struct query{int l,r,id;}q[51000];int as[51000];
bool cmp(query q1,query q2){return st[q1.l]==st[q2.l]?q1.r<q2.r:st[q1.l]<st[q2.l];}

int L[51000],R[51000];
int top,Lid[51000],Rid[51000],Ld[51000],Rd[51000];
void push(int ll,int rr)
{
    top++;
    Lid[top]=ll,Ld[top]=L[ll];
    Rid[top]=rr,Rd[top]=R[rr];
}
void pop()
{    
    while(top>0)
    {
        L[Lid[top]]=Ld[top];
        R[Rid[top]]=Rd[top];
        top--;
    }
}
int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
        
    block=int(sqrt(double(n+1)))+1;
    for(int i=1;i<=n;i++)st[i]=(i-1)/block+1;
    sort(q+1,q+m+1,cmp);
    
    int las=1;
    for(int b=1;b<=block;b++)
    {
        int mmax=0,r=b*block;
        memset(L,0,sizeof(L));
        memset(R,0,sizeof(R));
        for(int i=las;st[q[i].l]==b&&i<=m;i++,las=i)
        {
            while(q[i].r>r)
            {
                r++;
                L[c[r]]=L[c[r]-1]+1;
                R[c[r]]=R[c[r]+1]+1;
                
                int d=L[c[r]]+R[c[r]]-1;
                L[c[r]+R[c[r]]-1]=d;
                R[c[r]-L[c[r]]+1]=d;
                mmax=max(mmax,d);
            }
            
            as[q[i].id]=mmax;
            int li=min(q[i].r,b*block);
            for(int j=q[i].l;j<=li;j++)
            {
                L[c[j]]=L[c[j]-1]+1;
                R[c[j]]=R[c[j]+1]+1;
                
                int d=L[c[j]]+R[c[j]]-1;
                int ll=c[j]+R[c[j]]-1,rr=c[j]-L[c[j]]+1;
                push(ll,rr);
                L[ll]=d;
                R[rr]=d;
                as[q[i].id]=max(as[q[i].id],d);
            }
            
            pop();
            for(int j=q[i].l;j<=li;j++)L[c[j]]=R[c[j]]=0;
        }
    }
    
    for(int i=1;i<=m;i++)printf("%d\n",as[i]);
    return 0;
}

 

posted @ 2019-01-07 16:02  AKCqhzdy  阅读(272)  评论(0编辑  收藏  举报