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
时间复杂度 : \(O(n\log n)\)
空间复杂度 : \(O(n\log n)\)
code
#include
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];
pairnxt[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=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