傳送門
解析:
這道題真的就是防題了,但是對於我這個蒟蒻來說三道題都是防題,爲什麼說這道題是防題呢,主要是爲了阻止AK的步伐。
蒟蒻考場上打了暴力靠着常數優化勉強卡了,墊底滾粗了。。。
思路:
有點分治的味道,但不是分治。。。
首先的房頂到的房頂的距離是。其實很好理解,我們必須先走到最低的地方繞過去才能過去。
顯然我們計算能否從的房頂達到的房頂可以,如果預處理區間最小值可以。但是要統計所有的話這個就顯得有點吃力了。
那麼考慮分治,每次選取一個區間,以中間點爲分界線統計每個中的點能夠到達多少在中的點,反過來也是一樣的。
然後遞歸處理和兩個區間,顯然這樣處理是不重不漏的。
然後就是處理的重頭戲了。
定義
那麼和的距離就是
那麼就是
那麼我們把式子拆開,把與有關的放在一起,與有關的放在一起。
那麼我們要統計中的點對中的點的答案的貢獻
其實就是用去減一下,然後維護結果個數的後綴和就行了,這個樹狀數組和平衡樹都可以做。
要查詢的時候就直接按照後綴和查就行了。
其實這裏就是的思想,我們將所有點按照排序,然後對於我們要統計的部分查詢,否則修改就行了。
注意要處理兩種情況,每種兩種方向,一共四種情況。
代碼:
#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;
}