题目
题解
–谁知道这道水题O(n^2)暴力有90分,当然是要动脑筋,我就不讲了
谁又知道这道题要用权值线段树维护,来拿最后那十分
(代码量 * 10 == 分数 * 10/9)QAQ
首先权值线段树就是把原来存下标的 l 和 r 改成了存数值大小
所以说,左子树一定 < 右子树的值
对于这道题呢
我们要维护:
答案(就是相减最小绝对值和长度,取最大值)
最小值
最大值
与他权值相同的数量(合并到一个点)
然后就是子树向根的转移:
1. 对于答案:
继承左儿子
继承右儿子
右儿子的最小值 - 左儿子的最大值
2. 对于最小(大)值:
继承左儿子
继承右儿子
其实,具体方法就是:
如果目前区间[l,r]差的最小值<区间长度,那么我们可以r++,可能差的最小值就会进一步减小
但是如果区间长度>=差的最小值,现在r++是没有意义的(答案不可能再减小了),所以我们就l++
权值线段树的目的就是快速的找到加入一个被移入目标区间的点后,与他相邻最近的点的绝对值之差(可能作为新的最小值)
还有快速的删去一个被移出的点对答案的贡献
最后还可以离散化一下,去个重,加个速
复杂度应该是O(nlogn)的吧
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e6+5;
int n;
int ans=0x3f3f3f3f;
struct hihi{
int x;
int y;
}a[MAXN];
int b[MAXN],tot,c[MAXN];
struct hehe{
int minn;
int maxx;
int size;
int ans;
}tree[MAXN*4];
bool comp(const hihi &a,const hihi &b){
return a.x<b.x;
}
void lisan(){
for(int i=1;i<=n;i++){
if(a[i].x!=a[i-1].x)
tot++;
b[tot]=a[i].x;
c[a[i].y]=tot;
}
}
void add(int i,int x,int y,int z,int size){
if(x==y){
tree[i].size+=size;
if(tree[i].size){
tree[i].minn=x;
tree[i].maxx=y;
}
else{
tree[i].minn=0x3f3f3f3f;
tree[i].maxx=0;
}
if(tree[i].size>2)
tree[i].ans=0;
else
tree[i].ans=0x3f3f3f3f;
}
else{
int l=2*i,r=l+1;
int mid=(x+y)/2;
if(z<=mid)
add(l,x,mid,z,size);
else
add(r,mid+1,y,z,size);
tree[i].ans=min(tree[l].ans,tree[r].ans);
if(tree[l].maxx&&tree[r].minn!=0x3f3f3f3f)
tree[i].ans=min(tree[i].ans,b[tree[r].minn]-b[tree[l].maxx]);
tree[i].minn=min(tree[l].minn,tree[r].minn);
tree[i].maxx=max(tree[l].maxx,tree[r].maxx);
}
}
int main(){
freopen("random.in","r",stdin);
freopen("random.out","w",stdout);
cin>>n;
if(!n)
return 0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i].x);
a[i].y=i;
}
sort(a+1,a+1+n,comp);
lisan();
for(int i=1;i<=4*n;i++){
tree[i].ans=0x3f3f3f3f;
tree[i].size=0;
tree[i].minn=0x3f3f3f3f;
tree[i].maxx=0;
}
int l=1,r=2;
add(1,1,tot,c[l],1);
add(1,1,tot,c[r],1);
while(r<=n){
ans=min(ans,max(tree[1].ans,r-l+1));
if(l+1==r||tree[1].ans>r-l+1){
if(r==n)
break;
r++;
add(1,1,tot,c[r],1);
}
else{
add(1,1,tot,c[l],-1);
l++;
}
}
cout<<ans;
return 0;
}