1. 程式人生 > 其它 >「AHOI / HNOI2017」影魔

「AHOI / HNOI2017」影魔

「AHOI / HNOI2017」影魔

cdq 分治寫法。

首先利用單調棧求出 \(L_i,R_i\) 分別表示在 \(i\) 左邊第一個 \(K\) 值大於 \(K_i\),右邊第一個 \(K\) 值大於 \(K_i\) 的位置。

\(L_i\) 不存在設為 0,如 \(R_i\) 不存在設為 \(n+1\)

然後我們考慮提供 \(p1\) 攻擊力的情況:

容易發現對於一個點 \(i\),以及一個詢問 \(l,r\)。如果 \(l,r\) 同時包含 \(L_i,i\) 那麼 \(i\) 會對詢問產生 \(p1\) 的貢獻。如果 \(l,r\) 同時包含 \(i,R_i\),那麼 \(i\) 會對詢問產生 \(p1\)

的貢獻。

形式化的說,也就是 \(l\le L_i\le i\le r\) 的時候會產生貢獻,\(l\le i\le R_i\le r\) 的時候會產生貢獻。那麼這是個二維偏序問題,可以用 cdq 分治來解決。具體實現是將詢問看成點,\(l,r\) 看做權值,並將每個 \(i\) 拆成兩個點,權值分別為 \(L_i,i\)\(i,R_i\)

然後我們考慮提供 \(p2\) 攻擊力的情況:

對於一個點 \(i\),我們考慮其為 \(c\) 的情況。容易發現對於一個詢問 \(l,r\)。當 \(l,r\) 包含 \(L_i,i,R_i\) 時,那麼它對詢問會產生 \((R_i-L_i-2)\times p2\)

的貢獻。

\(l,r\) 包含 \(L_i,i\) 時,他會對詢問產生 \((r-i)*p2\) 的貢獻。

\(l,r\) 包含 \(i,R_i\) 時,他會對詢問產生 \((i-l)*p2\) 的貢獻。

抽象成表示式就是 \(l\le L_i< i< R_i\le r\)\(l\le L_i<i\le r<R_i\)\(L_i<l\le i < R_i\le r\)。這三種情況,易發現這個是個三維偏序。可以用 cdq 分治來處理。處理方法同上,將詢問看成點,並賦予三個權值。

實現起來有較多細節包括但不限於:

  1. 如果權值相等將詢問放在前面。
  2. 排序解決的那一維可能會包含相等的情況,而雙指標處理的部分不會包含相等的情況,所以只能用雙指標或樹狀陣列處理 \(<\) 號,因此得多 cdq 幾次。

由於 \(n,m\) 同階。因此時間複雜度為 \(O(n\log^2 n)\) 。外加大常數,請開 O2。

程式碼如下:

#include<bits/stdc++.h>
#define ll long long
#define lowbit(i) (i&(-i))
using namespace std;
const int MAXN = 2e5+5;
bool Small;
int n,m,p1,p2,A[MAXN];
int st[MAXN],top,L[MAXN],R[MAXN],le[MAXN],ri[MAXN];
bool Sunny;
struct BIT
{
	int t[MAXN];
	void add(int pos,int x)
	{
		for(int i=pos;i<=n;i+=lowbit(i)) t[i]+=x;
	}
	ll que(int pos)
	{
		ll ans=0;
		for(int i=pos;i;i-=lowbit(i)) ans+=t[i];
		return ans;
	}
}v,cnt;
struct node
{
	int l,r,id,v;
}Q[MAXN<<2];
bool cmp1(node x,node y){return x.l==y.l?x.id>y.id:x.l>y.l;}
bool cmp2(node x,node y){return x.r==y.r?x.id>y.id:x.r<y.r;}
bool cmp3(node x,node y){return x.l==y.l?x.id>y.id:x.l<y.l;}
bool cmp4(node x,node y){return x.v==y.v?x.id>y.id:x.v<y.v;}
bool cmp5(node x,node y){return x.r==y.r?x.id>y.id:x.r>y.r;}
ll Ans[MAXN];
void solve1(int l,int r)
{
	if(l==r) return ;
	int mid=l+r>>1;
	solve1(l,mid);solve1(mid+1,r);
	sort(Q+l,Q+mid+1,cmp2);sort(Q+mid+1,Q+r+1,cmp2);
	int cur=mid+1;ll cnt=0;
	for(int i=l;i<=mid;++i)
	{
		while(Q[cur].r<=Q[i].r&&cur<=r) cnt+=(Q[cur].id==0),++cur;
		if(Q[i].id!=0) Ans[Q[i].id]+=cnt*p1;
	}
}
void solve2(int l,int r)
{
	if(l==r) return ;
	int mid=l+r>>1;
	solve2(l,mid);solve2(mid+1,r);
	sort(Q+l,Q+mid+1,cmp2);sort(Q+mid+1,Q+r+1,cmp2);
	int cur=mid+1;ll tmp=0;
	for(int i=l;i<=mid;++i)
	{
		while(Q[cur].r<=Q[i].r&&cur<=r)
		{
			if(Q[cur].id==0) tmp+=Q[cur].r-Q[cur].l-2;
			++cur;
		}
		if(Q[i].id!=0) Ans[Q[i].id]+=tmp*p2;
	}
	cur=r;
	for(int i=mid;i>=l;--i)
	{
		while(cur>=mid+1&&Q[cur].r>Q[i].r)
		{
			if(Q[cur].id==0)
			{
				v.add(Q[cur].v,Q[cur].v);
				cnt.add(Q[cur].v,1);
			}
			--cur;
		}
		if(Q[i].id!=0)
		{
			ll val=v.que(Q[i].r),c=cnt.que(Q[i].r);
			Ans[Q[i].id]+=(c*Q[i].r-val)*p2;
		}
	}
	for(int i=r;i>cur;--i)
	{
		if(Q[i].id==0)
		{
			v.add(Q[i].v,-Q[i].v);
			cnt.add(Q[i].v,-1);
		}
	}
}
void solve3(int l,int r)
{
	if(l==r) return ;
	int mid=l+r>>1;
	solve3(l,mid);solve3(mid+1,r);
	sort(Q+l,Q+mid+1,cmp3);sort(Q+mid+1,Q+r+1,cmp3);
	int cur=mid+1;
	for(int i=l;i<=mid;++i)
	{
		while(cur<=r&&Q[cur].l<Q[i].l)
		{
			if(Q[cur].id==0)
			{
				v.add(n-Q[cur].v+1,Q[cur].v);
				cnt.add(n-Q[cur].v+1,1);
			}
			++cur;
		}
		if(Q[i].id!=0)
		{
			ll val=v.que(n-Q[i].l+1),c=cnt.que(n-Q[i].l+1);
			Ans[Q[i].id]+=(val-c*Q[i].l)*p2;
		}
	}
	for(int i=mid+1;i<cur;++i)
	{
		if(Q[i].id==0)
		{
			v.add(n-Q[i].v+1,-Q[i].v);
			cnt.add(n-Q[i].v+1,-1);
		}
	}
}
int main()
{
//	cout<<1.0*(&Sunny-&Small)/1024/1024<<"MB"<<endl;
	scanf("%d %d %d %d",&n,&m,&p1,&p2);
	for(int i=1;i<=n;++i)
		scanf("%d",&A[i]);
	for(int i=1;i<=n;++i)
	{
		while(top&&A[st[top]]<A[i])
		{
			R[st[top]]=i;
			--top;
		}
		if(top) L[i]=st[top];
		st[++top]=i;
	}
	for(int i=1;i<=n;++i) if(R[i]==0) R[i]=n+1;
	for(int i=1;i<=m;++i) scanf("%d %d",&le[i],&ri[i]);
	for(int i=1;i<=m;++i) Q[i]=node{le[i],ri[i],i,0};
	for(int i=1;i<=n;++i) Q[i+m]=node{i,R[i],0,0},Q[i+m+n]=node{L[i],i,0,0};
	sort(Q+1,Q+m+2*n,cmp3);solve1(1,m+2*n);
	for(int i=1;i<=m;++i) Q[i]=node{le[i],ri[i],i,0};
	for(int i=1;i<=n;++i) Q[i+m]=node{L[i],R[i],0,i};
	sort(Q+1,Q+1+n+m,cmp3);solve2(1,m+n);
	sort(Q+1,Q+1+n+m,cmp5);solve3(1,m+n);
	for(int i=1;i<=m;++i) printf("%lld\n",Ans[i]);
	return 0;
}
路漫漫其修遠兮,吾將上下而求索。