这题一开始傻逼了想了好久笛卡尔树之类的东西,然后一写发现错了。。然后思考了一下又想了个笛卡尔树上的,一写发现又错了。。
考虑扫右端点,设当前扫到了i,那么对于每个j < i,设 xj=max{ak}(j≤k≤i),yj=min{ak}(j≤k≤i) ,就是要求 min{j}((xj−yj)−(i−j)≤k) ,即 min{j}(xj−yj+j≤k+i) 。所以我们只需维护区间[l,r]中的 min{xj−yj+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);
}
}
总结:
①写之前一定要仔细想,想好每一个细节,不要没考虑清楚就开始写——那样会浪费很多时间!