cf500e New Year Domino

\(n\) 个多米诺骨牌,从左到右排列,每一个骨牌都有一个高度 \(L_i\),向右推倒,它会直接向右倒下,如下图,倒下后该骨牌的顶端落在 \(X_i+L_i\) 的位置, ( \(X_i\) 是它位于的坐标,即倒下时该骨牌不会发生移动)

在倒下过程中,骨牌会碰到其他骨牌,碰到的骨牌会向右倒,如下图,最左边的骨牌倒下会碰倒 \(A,B,C\)\(A,B,C\) 会倒下,但是不会直接碰到 \(D\) ,但是 \(D\) 会因为 \(C\) 的倒下而碰倒。

现在给你N个骨牌的坐标 \(X_i\) ,和每个骨牌的高度 \(L_i\) 。则一个骨牌能碰倒另一个骨牌当切仅当 \(X_i+l_i\geq x_j\)。同时有 \(Q\) 个询问 \([L,R]\) ,问向右推到第 \(L\) 个骨牌,最少需要多少代价让 \(R\) 倒下。你可以临时增加某个骨牌的高度,增加 \(1\) 个高度的代价是 \(1\) .

\(2\leq n\leq 2\cdot 10^5,1\leq P_i,L_i\leq 10^9,1\leq q\leq 2\cdot 10^5,1\leq l\leq r\leq n\)

推到第 \(i\) 个骨牌,能倒下的最后一个骨牌的下一个是 \(nxt(i)\) ,发现 \(i\to nxt(i)\) 连边会变成一些森林.

对于一些骨牌连通块,考虑如果想要推到第 \(i+1\) 个骨牌,增高第 \(i\) 个骨牌的高度最优.

上述两个性质,就可以倍增了.

这题的代码也非常难写呢. 首先,倍增的答案计算细节很多,其次,考虑计算 \(nxt(i)\) 时,是 \(i+1\)\(P_j<P_i+L_i\) 的最后一个 \(j\) 中间的 \(nxt\) 的最大值,而不是 \(nxt(j)\) ,因为 \(nxt\) 不单调递增.

时间复杂度 : \(O(n\log n)\)

空间复杂度 : \(O(n\log n)\)

code

#include<bits/stdc++.h>
using namespace std;
char in[100005];
int iiter=0,llen=0;
inline char get(){
	if(iiter==llen)llen=fread(in,1,100000,stdin),iiter=0;
	if(llen==0)return EOF;
	return in[iiter++];
}
inline int rd(){
	char ch=get();while(ch<'0'||ch>'9')ch=get();
	int res=0;while(ch>='0'&&ch<='9')res=(res<<3)+(res<<1)+ch-'0',ch=get();
	return res;
}
inline void pr(long long res){
	if(res==0){putchar('0');return;}
	static int out[20];int len=0;
	while(res)out[len++]=res%10,res/=10;
	for(int i=len-1;i>=0;i--)putchar(out[i]+'0');
}
#define MP make_pair
#define FI first
#define SE second
const int N=2e5+10;
class SGT{
public:
	int ts[N<<2];
	void init(){memset(ts,0,sizeof(ts));}
	void upd(int x,int l,int r,int pos,int val){
		if(l==r){
			ts[x]=max(ts[x],val);
			return;
		}
		int mid=(l+r)>>1;
		if(pos<=mid)upd(x<<1,l,mid,pos,val);
		else upd(x<<1|1,mid+1,r,pos,val);
		ts[x]=max(ts[x<<1],ts[x<<1|1]);
	}
	int qry(int x,int l,int r,int cl,int cr){
		if(l==cl&&r==cr)return ts[x];
		int mid=(l+r)>>1;
		if(cr<=mid)return qry(x<<1,l,mid,cl,cr);
		else if(mid+1<=cl)return qry(x<<1|1,mid+1,r,cl,cr);
		else return max(qry(x<<1,l,mid,cl,mid),qry(x<<1|1,mid+1,r,mid+1,cr));
	}
}T1,T2;
int n,q;
int P[N],L[N],R[N];
pair<long long,int>nxt[20][N];
long long qry(int l,int r){
	int tmp=l;
	long long cost=0,res=nxt[19][l].FI;
	for(int k=19;k>=0;k--){
		if(r<=R[tmp]){
			res=min(res,cost);
			break;
		}	
		if(r<=R[nxt[k][tmp].SE])res=min(res,cost+nxt[k][tmp].FI);
		else cost+=nxt[k][tmp].FI,tmp=nxt[k][tmp].SE;
	}
	if(r<=R[tmp])res=min(res,cost);
	return res;
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	n=rd();
	for(int i=0;i<n;i++)P[i]=rd(),L[i]=rd();
	T1.init();T2.init();
	for(int i=0;i<n;i++)T1.upd(1,0,n-1,i,P[i]+L[i]);
	R[n]=n;
	nxt[0][n-1]=MP(0,n);R[n-1]=n-1;
	T2.upd(1,0,n-1,n-1,n);
	for(int i=n-2;i>=0;i--){
		int pos=upper_bound(P,P+n,P[i]+L[i])-P-1;
		nxt[0][i].SE=pos>i?T2.qry(1,0,n-1,i+1,pos):i+1;
		T2.upd(1,0,n-1,i,nxt[0][i].SE);
		nxt[0][i].FI=nxt[0][i].SE==n?0:P[nxt[0][i].SE]-T1.qry(1,0,n-1,i,nxt[0][i].SE-1);
		R[i]=nxt[0][i].SE-1;
	}
	for(int k=0;k+1<20;k++){
		for(int i=0;i<n;i++){
			nxt[k+1][i].FI=nxt[k][i].FI;
			if(nxt[k][i].SE<n){
				nxt[k+1][i].FI+=nxt[k][nxt[k][i].SE].FI;
				nxt[k+1][i].SE=nxt[k][nxt[k][i].SE].SE;
			}else nxt[k+1][i].SE=nxt[k][i].SE;
		}
	}
	q=rd();
	for(int i=0;i<q;i++){
		int l=rd()-1,r=rd()-1;
		pr(qry(l,r));
		putchar('\n');
	}
	return 0;
}
/*inline? ll or int? size? min max?*/

posted @ 2022-01-07 22:11  xyangh  阅读(11)  评论(0)    收藏  举报