CF765F Souvenirs
Utilokasteinn · · 题解
Link
题目大意:
已知一个长度为
数据范围:
这道题容易想到莫队套平衡树的
翻了下题解发现有 乱搞做法,居然可以过去。
这里再写一篇分块的解法。
分块,设块长为
设
块内升序排序,并且记录下标。时间复杂度
设
以下只说
容易求出
考虑如何得到
用容斥的思想,可以发现
直接求
然后用区间动规的思想合并即可。时间复杂度
查询时,一个散块加一个整块的答案可以直接得知。考虑如何求两个散块的答案。
其实和预处理一样,把排序完的数组扫一遍就好了。时间复杂度
当
单次查询时间复杂度
然后本题就做完了,时间复杂度
代码如下:
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int s=0;char c=getchar();
for(;!isdigit(c);c=getchar());
for(;isdigit(c);c=getchar())
s=s*10+c-'0';
return s;
}
int n,m,a[100005];
pair<int,int>b[100005];
int len,block,L[320],R[320],pos[100005];
int pre[320][100005],nxt[320][100005];
int ans[100005];
void get_ans(int p,int q)
{
int pos=L[p];
for(int i=L[q];i<=R[q];i++)
{
int x=b[i].first;
while(pos<R[p]&&b[pos+1].first<=x)pos++;
int y=b[pos].first,z=pos+1>R[p]?y:b[pos+1].first;
ans[b[i].second]=min(abs(x-y),abs(x-z));
}
}
void input()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=b[i].first=read(),b[i].second=i;
len=sqrt(n),block=n/len;
for(int i=1;i<=block;i++)
L[i]=R[i-1]+1,R[i]=i*len;
R[block]=n;
for(int i=1;i<=block;i++)
{
sort(b+L[i],b+R[i]+1);
for(int j=L[i];j<=R[i];j++)
{
pos[j]=i;
int minn=2e9;
for(int k=L[i];k<j;k++)
minn=min(minn,abs(a[j]-a[k]));
if(j==L[i])pre[i][j]=2e9;
else pre[i][j]=min(pre[i][j-1],minn);
}
for(int j=R[i];j>=L[i];j--)
{
int minn=2e9;
for(int k=R[i];k>j;k--)
minn=min(minn,abs(a[j]-a[k]));
if(j==R[i])nxt[i][j]=2e9;
else nxt[i][j]=min(nxt[i][j+1],minn);
}
}
for(int len=2;len<=block;len++)
{
for(int i=1;i+len-1<=block;i++)
{
int k=i+len-1;
get_ans(i,k);
for(int j=L[k];j<=R[k];j++)
pre[i][j]=min(pre[i][j-1],min(pre[i+1][j],ans[j]));
}
for(int i=block;i-len+1>=1;i--)
{
int k=i-len+1;
get_ans(i,k);
for(int j=R[k];j>=L[k];j--)
nxt[i][j]=min(nxt[i][j+1],min(nxt[i-1][j],ans[j]));
}
}
}
int temp[320];
inline int query(int l,int r)
{
int p=pos[l],q=pos[r],res=2e9,pos=1,tot=0;
if(p==q)
{
for(int i=L[p];i<=R[p];i++)
if(l<=b[i].second&&b[i].second<=r)
temp[++tot]=b[i].first;
for(int i=L[p];i<=R[p];i++)
{
if(b[i].second<l||r<b[i].second)continue;
int x=b[i].first;
while(pos<tot&&temp[pos+1]<=x)pos++;
int y=pos==1?2e9:temp[pos-1],z=pos+1>tot?y:temp[pos+1];
res=min(res,min(abs(x-y),abs(x-z)));
}
return res;
}
for(int i=L[q];i<=R[q];i++)
if(L[q]<=b[i].second&&b[i].second<=r)
temp[++tot]=b[i].first;
for(int i=L[p];i<=R[p];i++)
{
if(b[i].second<l||R[p]<b[i].second)continue;
int x=b[i].first;
while(pos<tot&&temp[pos+1]<=x)pos++;
int y=temp[pos],z=pos+1>tot?y:temp[pos+1];
res=min(res,min(abs(x-y),abs(x-z)));
}
return min(res,min(nxt[q-1][l],pre[p+1][r]));
}
void solve()
{
m=read();
while(m--)
{
int l=read(),r=read();
printf("%d\n",query(l,r));
}
}
int main()
{
input();
solve();
return 0;
}