[bzoj4527]K-D-Sequence 解题报告

这题一开始傻逼了想了好久笛卡尔树之类的东西,然后一写发现错了。。然后思考了一下又想了个笛卡尔树上的,一写发现又错了。。
考虑扫右端点,设当前扫到了i,那么对于每个j < i,设 xj=max{ak}(jki),yj=min{ak}(jki) ,就是要求 min{j}((xjyj)(ij)k) ,即 min{j}(xjyj+jk+i) 。所以我们只需维护区间[l,r]中的 min{xjyj+j},min{xj+j},min{yj+j},min{j} 即可。然后每次扫到一个端点,将它最左合法左端点之前的点清为 ,将它左边第一个大于它的点+1到它这段区间的x覆盖为 ai ,将它左边第一个小于它的点+1到它这段区间的y覆盖为 ai ,然后查询的时候在线段树上二分即可。
代码:

#include<cstdio>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cassert>
const int N=2e5+5,K=2e5+5,D=1e9+5;
int a[N];
int n,d;
const int inf=0x7fffffff;

char * cp=(char *)malloc(3000000);
void in(int &x){
    bool flag=0;
    while(*cp<'0'||*cp>'9')flag=*cp++=='-';
    for(x=0;*cp>='0'&&*cp<='9';)x=x*10+(*cp++^'0');
    if(flag)x=-x;
}

int bigq[N],smallq[N];
int hash[N];
int pos[N];

struct AS{
    int len,l;
};
AS max(const AS &a,const AS &b){
    if(a.len!=b.len)return a.len>b.len?a:b;
    else return a.l<b.l?a:b;
}

struct SS{
    int min[4];
    int a,b;
}segt[N<<2];
#define lson node<<1,l,l+r>>1
#define rson node<<1|1,(l+r>>1)+1,r
void out(int node,int l,int r){
    printf("segt[%d][%d,%d]={min[0]=%d,min[1]=%d,min[2]=%d,min[3]=%d,a=%d,b=%d}\n",node,l,r,segt[node].min[0],segt[node].min[1],segt[node].min[2],segt[node].min[3],segt[node].a,segt[node].b);
}
void outdfs(int node,int l,int r){
    out(node,l,r);
    if(l!=r&&segt[node].a==inf&&segt[node].b==inf)outdfs(lson),outdfs(rson);
}
void pushup(int node){
    for(int i=4;i--;)segt[node].min[i]=min(segt[node<<1].min[i],segt[node<<1|1].min[i]);
}
void painta(int node,int a){
    if(segt[node].min[0]!=inf){
        segt[node].min[0]=a+segt[node].min[2];
        segt[node].min[1]=a+segt[node].min[3];
        segt[node].a=a;
    }
}
void paintb(int node,int b){
    if(segt[node].min[0]!=inf){
        segt[node].min[0]=b+segt[node].min[1];
        segt[node].min[2]=b+segt[node].min[3];
        segt[node].b=b;
    }
}
void pushdown(int node){
    if(segt[node].a!=inf){
        painta(node<<1,segt[node].a),painta(node<<1|1,segt[node].a);
        segt[node].a=inf;
    }
    if(segt[node].b!=inf){
        paintb(node<<1,segt[node].b),paintb(node<<1|1,segt[node].b);
        segt[node].b=inf;
    }
}
void build(int node,int l,int r){
    for(int i=4;i--;)segt[node].min[i]=inf;
    segt[node].a=segt[node].b=inf;
    if(l!=r)build(lson),build(rson);
}
void updatea(int node,int l,int r,int L,int R,int a){
    if(L<=l&&r<=R)painta(node,a);
    else{
        pushdown(node);
        if(L<=l+r>>1)updatea(lson,L,R,a);
        if(R>l+r>>1)updatea(rson,L,R,a);
        pushup(node);
    }
}
void updateb(int node,int l,int r,int L,int R,int b){
    if(L<=l&&r<=R)paintb(node,b);
    else{
        pushdown(node);
        if(L<=l+r>>1)updateb(lson,L,R,b);
        if(R>l+r>>1)updateb(rson,L,R,b);
        pushup(node);
    }
}
void update(int node,int l,int r,int x){
    if(l==r)
        if(segt[node].min[0]==inf)
            for(int i=4;i--;)
                segt[node].min[i]=l;
        else
            for(int i=4;i--;)
                segt[node].min[i]=inf;
    else{
        pushdown(node);
        if(x<=l+r>>1)update(lson,x);
        else update(rson,x);
        pushup(node);
    }
}
int query(int node,int l,int r,int uplimit){
    if(segt[node].min[0]>uplimit)return n+1;
    while(l!=r){
        //out(node,l,r);
        pushdown(node);
        if(segt[node<<1].min[0]<=uplimit)node<<=1,r=l+r>>1;
        else node=node<<1|1,l=(l+r>>1)+1;
    }
    return l;
}
int main(){
    freopen("bzoj_4527.in","r",stdin);
    freopen("bzoj_4527.out","w",stdout);

    fread(cp,1,3000000,stdin);

    int k;
    in(n),in(k),in(d);
    for(int i=1;i<=n;++i)in(a[i]);

    AS ans=(AS){-1,0};
    if(d==0){
        int l=1;
        a[0]=inf;
        for(int i=1;i<=n;++i)
            if(a[i]!=a[i-1]){
                //cout<<"Get{"<<i-l<<','<<l<<"} at "<<i<<endl;
                ans=max(ans,(AS){i-l,l});
                l=i;
            }
        ans=max(ans,(AS){n-l+1,l});
        printf("%d %d\n",ans.l,ans.l+ans.len-1);
    }
    else{
        for(int i=n;i;--i)hash[i-1]=a[i];
        sort(hash,hash+n);
        int htot=unique(hash,hash+n)-hash;

        build(1,1,n);
        int hashed;
        int l=1,prel=1;
        int bigh=0,bigt=0;
        int smallh=0,smallt=0;
        int nowl;
        int tmp;
        for(int i=1;i<=n;++i){

            //printf("----%d-----\n",i);

            if((a[i]%d+d)%d!=(a[i-1]%d+d)%d)l=i;
            hashed=lower_bound(hash,hash+htot,a[i])-hash;
            //cout<<hashed<<endl;
            l=max(l,pos[hashed]+1);
            pos[hashed]=i;

            //printf("l=%d\n",l);

            while(prel<l)update(1,1,n,prel++);
            update(1,1,n,i);
            tmp=floor((double)a[i]/d);

            //printf("tmp=%d\n",tmp);

            while(bigh!=bigt&&bigq[bigh]<l)++bigh;
            while(bigh!=bigt&&a[bigq[bigt-1]]<a[i])--bigt;
            if(bigh!=bigt)updatea(1,1,n,bigq[bigt-1]+1,i,tmp);
            else updatea(1,1,n,l,i,tmp);
            bigq[bigt++]=i;

            while(smallh!=smallt&&smallq[smallh]<l)++smallh;
            while(smallh!=smallt&&a[smallq[smallt-1]]>a[i])--smallt;
            if(smallh!=smallt)updateb(1,1,n,smallq[smallt-1]+1,i,-tmp);
            else updateb(1,1,n,l,i,-tmp);
            smallq[smallt++]=i;

            nowl=query(1,1,n,k+i);

            ans=max(ans,(AS){i-nowl,nowl});

            //outdfs(1,1,n);
        }

        printf("%d %d\n",ans.l,ans.l+ans.len);
    }
}

总结:
①写之前一定要仔细想,想好每一个细节,不要没考虑清楚就开始写——那样会浪费很多时间!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值