传送门
解析:
这道题真的就是防 A K AK AK题了,但是对于我这个蒟蒻来说三道题都是防 A K AK AK题,为什么说这道题是防 A K AK AK题呢,主要是为了阻止 l d x o i ldxoi ldxoiAK的步伐。
蒟蒻考场上打了 30 p t s 30pts 30pts暴力靠着常数优化勉强卡了 60 p t s 60pts 60pts,垫底滚粗了。。。
思路:
有点 c d q cdq cdq分治的味道,但不是 c d q cdq cdq分治。。。
首先 i i i的房顶到 j j j的房顶 ( i < j ) (i<j) (i<j)的距离是 h i + h j + j − i − 2 × m i n { h i , h i + 1 . . . h j } h_i+h_j+j-i-2\times min\{h_i,h_{i+1}...h_j\} hi+hj+j−i−2×min{hi,hi+1...hj}。其实很好理解,我们必须先走到最低的地方绕过去才能过去。
显然我们计算能否从 i i i的房顶达到 j j j的房顶可以 O ( n ) O(n) O(n),如果预处理区间最小值可以 O ( 1 ) O(1) O(1)。但是要统计所有的话这个就显得有点吃力了。
那么考虑分治,每次选取一个区间 < l , r > <l,r> <l,r>,以中间点 m i d = ( l + r ) / 2 mid=(l+r)/2 mid=(l+r)/2为分界线统计每个 l − m i d l-mid l−mid中的点能够到达多少在 m i d + 1 − r mid+1-r mid+1−r中的点,反过来也是一样的。
然后递归处理 l − m i d l-mid l−mid和 m i d + 1 − r mid+1-r mid+1−r两个区间,显然这样处理是不重不漏的。
然后就是处理的重头戏了。
定义 m i n n i = { m i n { h i , h i + 1 . . . h m i d } ( i ≤ m i d ) m i n { h i , h i − 1 . . . h m i d + 1 } ( i ≥ m i d ) minn_i=\begin{cases} min\{h_i,h_{i+1}...h_{mid}\}& (i\leq mid)\\ min\{h_i,h_{i-1}...h_{mid+1}\}& (i\geq mid) \end{cases} minni={min{hi,hi+1...hmid}min{hi,hi−1...hmid+1}(i≤mid)(i≥mid)
那么 i i i和 j j j的距离就是 h i + h j + j − i − 2 × m i n { m i n n i , m i n n j } h_i+h_j+j-i-2\times min\{minn_i,minn_j\} hi+hj+j−i−2×min{minni,minnj}
那么就是 d i s t ( i , j ) = { h i + h j + j − i − 2 × m i n n i ( m i n n i < m i n n j ) h i + h j + j − i − 2 × m i n n j ( m i n n i ≥ m i n n j ) dist(i,j)=\begin{cases} h_i+h_j+j-i-2\times minn_i&(minn_i<minn_j)\\ h_i+h_j+j-i-2\times minn_j&(minn_i\geq minn_j) \end{cases} dist(i,j)={hi+hj+j−i−2×minnihi+hj+j−i−2×minnj(minni<minnj)(minni≥minnj)
那么我们把式子拆开,把与 i i i有关的放在一起,与 j j j有关的放在一起。
那么我们要统计 l − m i d l-mid l−mid中的点对 m i d + 1 − r mid+1-r mid+1−r中的点的答案的贡献
其实就是用 k k k去减一下,然后维护结果个数的后缀和就行了,这个树状数组和平衡树都可以做。
要查询的时候就直接按照后缀和查就行了。
其实这里就是 c d q cdq cdq的思想,我们将所有点按照 m i n n minn minn排序,然后对于我们要统计的部分查询,否则修改就行了。
注意要处理两种情况,每种两种方向,一共四种情况。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
vector<int> all,bit;
inline void init(){
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());
bit.assign(all.size()+1,0);
}
inline void add(int pos){
pos=upper_bound(all.begin(),all.end(),pos)-all.begin();
for(;pos;pos-=(pos&(-pos)))++bit[pos];
}
inline int query(int pos){
re int res=0;
pos=lower_bound(all.begin(),all.end(),pos)-all.begin()+1;
for(;pos<bit.size();pos+=(pos&(-pos)))res+=bit[pos];
return res;
}
struct node{
int val,pos;
node(cs int &_pos=0,cs int &_val=0):pos(_pos),val(_val){}
friend bool operator<(cs node &a,cs node &b){
return a.val<b.val;
}
};
cs int N=100005;
int ans[N],h[N],minn[N],n,k;
inline void solve(int l,int r){
if(l==r)return (void)++ans[l];
int mid=(l+r)>>1;
vector<node> vec;
minn[mid]=h[mid];
for(int re i=mid-1;i>=l;--i)minn[i]=min(minn[i+1],h[i]);
minn[mid+1]=h[mid+1];
for(int re i=mid+2;i<=r;++i)minn[i]=min(minn[i-1],h[i]);
for(int re i=l;i<=r;++i)vec.push_back(node(i,minn[i]));
sort(vec.begin(),vec.end());
all.clear();
for(int re i=l;i<=mid;++i)all.push_back(k-h[i]+i+2*minn[i]);
init();
for(int re i=0;i<vec.size();++i){
node &t=vec[i];
if(t.pos<=mid)add(k-h[t.pos]+t.pos+2*minn[t.pos]);
else ans[t.pos]+=query(h[t.pos]+t.pos);
}
all.clear();
for(int re i=l;i<=mid;++i)all.push_back(k-h[i]+i);
init();
for(int re i=vec.size()-1;~i;--i){
node &t=vec[i];
if(t.pos<=mid)add(k-h[t.pos]+t.pos);
else ans[t.pos]+=query(h[t.pos]+t.pos-minn[t.pos]*2);
}
all.clear();
for(int re i=mid+1;i<=r;++i)all.push_back(k-h[i]-i+2*minn[i]);
init();
for(int re i=0;i<vec.size();++i){
node &t=vec[i];
if(t.pos>mid)add(k-h[t.pos]-t.pos+minn[t.pos]*2);
else ans[t.pos]+=query(h[t.pos]-t.pos);
}
all.clear();
for(int re i=mid+1;i<=r;++i)all.push_back(k-h[i]-i);
init();
for(int re i=vec.size()-1;~i;--i){
node &t=vec[i];
if(t.pos>mid)add(k-h[t.pos]-t.pos);
else ans[t.pos]+=query(h[t.pos]-t.pos-minn[t.pos]*2);
}
solve(l,mid);
solve(mid+1,r);
}
signed main(){
n=getint();
k=getint();
for(int re i=1;i<=n;++i)h[i]=getint();
solve(1,n);
for(int re i=1;i<=n;++i)printf("%d ",ans[i]);
return 0;
}