2018.10.24【校內模擬】小 C 的宿舍(分治)

傳送門


解析:

這道題真的就是防AKAK題了,但是對於我這個蒟蒻來說三道題都是防AKAK題,爲什麼說這道題是防AKAK題呢,主要是爲了阻止ldxoildxoiAK的步伐。

蒟蒻考場上打了30pts30pts暴力靠着常數優化勉強卡了60pts60pts,墊底滾粗了。。。

思路:

有點cdqcdq分治的味道,但不是cdqcdq分治。。。

首先ii的房頂到jj的房頂(i<j)(i<j)的距離是hi+hj+ji2×min{hi,hi+1...hj}h_i+h_j+j-i-2\times min\{h_i,h_{i+1}...h_j\}。其實很好理解,我們必須先走到最低的地方繞過去才能過去。

顯然我們計算能否從ii的房頂達到jj的房頂可以O(n)O(n),如果預處理區間最小值可以O(1)O(1)。但是要統計所有的話這個就顯得有點吃力了。

那麼考慮分治,每次選取一個區間<l,r><l,r>,以中間點mid=(l+r)/2mid=(l+r)/2爲分界線統計每個lmidl-mid中的點能夠到達多少在mid+1rmid+1-r中的點,反過來也是一樣的。

然後遞歸處理lmidl-midmid+1rmid+1-r兩個區間,顯然這樣處理是不重不漏的。

然後就是處理的重頭戲了。

定義minni={min{hi,hi+1...hmid}(imid)min{hi,hi1...hmid+1}(imid)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}

那麼iijj的距離就是hi+hj+ji2×min{minni,minnj}h_i+h_j+j-i-2\times min\{minn_i,minn_j\}

那麼就是dist(i,j)={hi+hj+ji2×minni(minni<minnj)hi+hj+ji2×minnj(minniminnj)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}

那麼我們把式子拆開,把與ii有關的放在一起,與jj有關的放在一起。

那麼我們要統計lmidl-mid中的點對mid+1rmid+1-r中的點的答案的貢獻

其實就是用kk去減一下,然後維護結果個數的後綴和就行了,這個樹狀數組和平衡樹都可以做。

要查詢的時候就直接按照後綴和查就行了。

其實這裏就是cdqcdq的思想,我們將所有點按照minnminn排序,然後對於我們要統計的部分查詢,否則修改就行了。

注意要處理兩種情況,每種兩種方向,一共四種情況。


代碼:

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章