LOJ #3634. 「2021 集训队互测」音符大师
作者:互联网
题面传送门
首先好像有一道题交闹钟来着,是\(m=0\)的版本。
考虑设\(f_{i,j,0/1}\)为一个点在\([a_i-m,a_i]\)左/右,另一个点在\(j\)点的最小答案。
然后转移分类讨论:首先找到第一个不在\([a_i-m,a_i]\)区间内的位置\(x\),如果找不到直接贡献答案。
如果是这一步转移\(a_i\),那么相当于全局加一个数,然后合并。
如果这一步转移\(j\),再分类讨论:
如果\(j\)不被\([a_x-m,a_x]\)包含,那么相当于区间查询值正负下标的最小值,然后单点修改。
如果\(j\)被包含,那么向后找到两个区间都不包含的一个最近位置,然后单点修改即可。
容易发现上述过程可以用线段树维护,时间复杂度\(O(nm\log n)\)
写代码的时候重构了一次,加上本来的压行,代码已经不能看了qwq
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (50000+5)
#define M (2500000+5)
#define K (200000+5)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,k,x,y,z,A[N],Ns[N<<1],Nh,Id,L[N],R[N],Rs[N][2],Cnt,N1,N2,N3;ll Ans=1e18,Pus,G[60];
namespace TT{
#define ls now<<1
#define rs now<<1|1
queue<int> F[N<<3];int Val[N<<3];I void Up(int now){Val[now]=min(Val[ls],Val[rs]);}
I void Ins(int x,int y,int l=1,int r=Nh,int now=1){if(l==r) {F[now].push(y);Val[now]=F[now].front();return;}int m=l+r>>1;x<=m?Ins(x,y,l,m,ls):Ins(x,y,m+1,r,rs);Up(now);}
I void Del(int x,int l=1,int r=Nh,int now=1){if(l==r){F[now].pop();Val[now]=(F[now].empty()?1e9:F[now].front());return;}int m=l+r>>1;x<=m?Del(x,l,m,ls):Del(x,m+1,r,rs);Up(now);}
I void Qry(int x,int y,int &Ans,int l=1,int r=Nh,int now=1){if(x>y) return;if(Val[now]>=Ans) return;if(x<=l&&r<=y){Ans=Val[now];return;};int m=l+r>>1;x<=m&&(Qry(x,y,Ans,l,m,ls),0);y>m&&(Qry(x,y,Ans,m+1,r,rs),0);}
#undef ls
#undef rs
}
namespace Tree{
ll M1[M*6],M2[M*6],Fl[M*6];int L[M*6],R[M*6],cnt,st[M*6],H;I void Up(int now){M1[now]=min(M1[L[now]],M1[R[now]]);M2[now]=min(M2[L[now]],M2[R[now]]);}
I void PF(int now,ll w){now&&(Fl[now]+=w,M1[now]+=w,M2[now]+=w);}I void P(int now){Fl[now]&&(PF(L[now],Fl[now]),PF(R[now],Fl[now]),Fl[now]=0);}
I void Ins(int x,ll y,int &now,int l=1,int r=Nh){/*Cnt++;*/!now&&(now=(H?st[H--]:++cnt),L[now]=R[now]=Fl[now]=0,M1[now]=M2[now]=1e18);if(l==r){/*printf("%d %lld\n",x,y);*/M1[now]=min(M1[now],y-Ns[l]);M2[now]=min(M2[now],y+Ns[l]);return;}P(now);int m=l+r>>1;x<=m?Ins(x,y,L[now],l,m):Ins(x,y,R[now],m+1,r);Up(now);}
I ll Q1(int x,int y,int now,int l=1,int r=Nh){if(x<=l&&r<=y) return M1[now];int m=l+r>>1;ll F1=1e18,F2=1e18;P(now);x<=m&&(F1=Q1(x,y,L[now],l,m));y>m&&(F2=Q1(x,y,R[now],m+1,r));return min(F1,F2);}
I ll Q2(int x,int y,int now,int l=1,int r=Nh){if(x<=l&&r<=y) return M2[now];int m=l+r>>1;ll F1=1e18,F2=1e18;P(now);x<=m&&(F1=Q2(x,y,L[now],l,m));y>m&&(F2=Q2(x,y,R[now],m+1,r));return min(F1,F2);}
I int ME(int x,int y,int l=1,int r=Nh){if(!x||!y) return x|y;P(x);P(y);st[++H]=y;M1[x]=min(M1[x],M1[y]);M2[x]=min(M2[x],M2[y]);if(l==r)return x;int m=l+r>>1;L[x]=ME(L[x],L[y],l,m);R[x]=ME(R[x],R[y],m+1,r);/*Up(x);*/return x;}
I void calc(int now,int l=1,int r=Nh){if(!now) return;st[++H]=now;if(l==r) {/*if(now) printf("%d %lld\n",l,min(M1[now]+Ns[l],M2[now]+Ns[l]));*/Ans=min(Ans,min(M1[now]+Ns[l],M2[now]-Ns[l]));return;}P(now);int m=l+r>>1;calc(L[now],l,m);calc(R[now],m+1,r);}
I void NEW(int x,int &now,int l=1,int r=Nh){!now&&(now=(H?st[H--]:++cnt),L[now]=R[now]=Fl[now]=0,M1[now]=M2[now]=1e18);if(l==r) return;P(now);int m=l+r>>1;x<=m?NEW(x,L[now],l,m):NEW(x,R[now],m+1,r);Up(now);}
I void Find(int x,int y,int now,int l=1,int r=Nh){if(!now)return;if(l==r){G[l-x+1]=M1[now]+Ns[l];return;}int m=l+r>>1;P(now);x<=m&&(Find(x,y,L[now],l,m),0);y>m&&(Find(x,y,R[now],m+1,r),0);}
// I void Push(int x,int y,int z,int &now,int l=1,int r=Nh){!now&&(now=(H?st[H--]:++cnt),L[now]=R[now]=Fl[now]=0,M1[now]=M2[now]=1e18);if(l==r){M1[now]=min(M1[now],G[l-x+1][z]-Ns[l]);M2[now]=min(M2[now],G[l-x+1][z]+Ns[l]);return;}int m=l+r>>1;P(now);x<=m&&(Push(x,y,z,L[now],l,m),0);y>m&&(Push(x,y,z,R[now],m+1,r),0);Up(now);}
}
I int calc(int x,int y,int l,int r){/*Cnt-=clock();*/x>l&&(swap(x,l),swap(y,r),0);N1=N2=N3=1e9;TT::Qry(1,x-1,N1);TT::Qry(y+1,l-1,N2);TT::Qry(r+1,Nh,N3);/*Cnt+=clock();*/return min(N1,min(N2,N3));}
I void Solve(int X,int Y,int Ro){
N1=N2=1e9;TT::Qry(1,X-1,N1);TT::Qry(Id?(Y+1):(UB(Ns+1,Ns+Nh+1,Ns[X]+m)-Ns),Nh,N2);x=min(N1,N2);/*if(!Id) cerr<<x<<'\n';*/assert(x>Id);if(x>n) {Tree::calc(Ro);return;}
if(L[x]^1) /*cerr<<X<<' '<<Y<<' '<<Tree::Q1(1,L[x]-1,Ro)+Ns[L[x]]<<'\n',*/Tree::Ins(X,Tree::Q1(1,L[x]-1,Ro)+Ns[L[x]],Rs[x][0]);
if(R[x]^Nh) Tree::Ins(X,Tree::Q2(R[x]+1,Nh,Ro)-Ns[R[x]],Rs[x][1]);
Me(G,0x3f);Tree::Find(L[x],R[x],Ro);
for(RI i=L[x];i<=R[x];i++){
Pus=G[i-L[x]+1];if(Pus>1e17){/*Tree::NEW(i,Rs[y][0]);Tree::NEW(i,Rs[y][1]);Tree::NEW(X,Rs[y][0]);Tree::NEW(X,Rs[y][1]);*/continue;}y=calc(X,Y,i,UB(Ns+1,Ns+Nh+1,Ns[i]+m)-Ns-1);if(y>n){Ans=min(Ans,Pus);continue;}
if(X<L[y]) /*assert(Ns[L[y]]-Ns[X]>0),*/Tree::Ins(i,Pus+Ns[L[y]]-Ns[X],Rs[y][0]);else /*assert(Ns[X]-Ns[R[y]]>0),*/Tree::Ins(i,Pus+Ns[X]-Ns[R[y]],Rs[y][1]);
if(i<L[y]) /*assert(Ns[L[y]]-Ns[i]>0),*/Tree::Ins(X,Pus+Ns[L[y]]-Ns[i],Rs[y][0]);else /*assert(Ns[i]-Ns[R[y]]>0),*/Tree::Ins(X,Pus+Ns[i]-Ns[R[y]],Rs[y][1]);
}
if(X<L[x]) /*assert(Ns[L[x]]-Ns[X]>0),*/Tree::PF(Ro,Ns[L[x]]-Ns[X]),Rs[x][0]=Tree::ME(Rs[x][0],Ro);else /*cerr<<Id<<' '<<x<<' '<<X<<' '<<Y<<' '<<L[x]<<' '<<R[x]<<'\n',*//*assert(Ns[X]-Ns[R[x]]>0),*/Tree::PF(Ro,Ns[X]-Ns[R[x]]),Rs[x][1]=Tree::ME(Rs[x][1],Ro);
}
int main(){
freopen("1.in","r",stdin);//freopen("1.out","w",stdout);
RI i,j,h;Me(TT::Val,0x3f);Me(Tree::M1,0x3f);Me(Tree::M2,0x3f);scanf("%d%d",&n,&m);Ns[Nh=1]=0;for(i=1;i<=n;i++) {scanf("%d",&A[i]);Ns[++Nh]=A[i];Ns[++Nh]=A[i]-m;}sort(Ns+1,Ns+Nh+1);
Nh=unique(Ns+1,Ns+Nh+1)-Ns-1;for(i=1;i<=n;i++) L[i]=LB(Ns+1,Ns+Nh+1,A[i]-m)-Ns,R[i]=LB(Ns+1,Ns+Nh+1,A[i])-Ns;L[0]=R[0]=LB(Ns+1,Ns+Nh+1,0)-Ns;
for(i=0;i<=n;i++) TT::Ins(R[i],i);Tree::Ins(L[0],0,Rs[0][0]);for(i=0;i<=n;i++){//printf("%d\n",i);
Id=i;TT::Del(R[i]);Solve(L[i],R[i],Rs[i][0]);Solve(R[i],UB(Ns+1,Ns+Nh+1,Ns[R[i]]+m)-Ns-1,Rs[i][1]);
//
// for(j=L[i-1];j<=R[i-1];j++){
// if(j>=L[i]&&j<=R[i]) {R2[j-L[i]+1]=Tree::ME(R2[j-L[i]+1],R1[j-L[i-1]+1]);continue;}
// Tree::Find(L[i],R[i],j-L[i-1]+1,R1[j-L[i-1]+1]);
// //for(h=L[i];h<=R[i];h++) Tree::Ins(j,Tree::Q1(h,h,R1[j-L[i-1]+1])+Ns[h],R2[h-L[i]+1]);
// if(L[i]^1) Tree::Ins(j,Tree::Q1(1,L[i]-1,R1[j-L[i-1]+1])+Ns[L[i]],R2[1]);
// if(R[i]^Nh) Tree::Ins(j,Tree::Q2(R[i]+1,Nh,R1[j-L[i-1]+1])-Ns[R[i]],R2[R[i]-L[i]+1]);
//
// if(j<L[i]) Tree::PF(R1[j-L[i-1]+1],Ns[L[i]]-Ns[j]),R2[1]=Tree::ME(R2[1],R1[j-L[i-1]+1]);
// else Tree::PF(R1[j-L[i-1]+1],Ns[j]-Ns[R[i]]),R2[R[i]-L[i]+1]=Tree::ME(R2[R[i]-L[i]+1],R1[j-L[i-1]+1]);
// }
// for(j=L[i];j<=R[i];j++) Tree::Push(L[i-1],R[i-1],j-L[i]+1,R2[j-L[i]+1]);
}
//for(i=L[n];i<=R[n];i++) /*printf("%d\n",i-L[n]+1),*/Tree::calc(R2[i-L[n]+1]);
printf("%lld\n",Ans);cerr<<Cnt<<'\n';
}
/*20 5
1 5 5 6 1 18 13 5 1 11 3 1 9 1 1 1 5 6 4 1
20 5
1 20 9 20 9 4 6 1 8 13 6 19 13 9 5 5 16 9 5 8
*/
标签:Ns,LOJ,3634,int,M1,2021,M2,now,define 来源: https://www.cnblogs.com/275307894a/p/16070063.html