洛谷 P9624 [ICPC 2020 Nanjing R] Certain Scientific Railgun题解-被欧捏撒嘛折磨致死
被欧捏撒嘛调成啥了,超级难写。
思路
下文先不考虑离散化。
容易发现欧捏撒嘛走过的路是连续的,如果投影到 \(x\) 和 \(y\) 轴上,是两个连续的区间。
而如果把机器人也都映射到坐标轴上,这两个区间应该覆盖所有点。
对于确定的区间,在这一维最小的移动距离一定是 \(f(L,R)=\min(|L|,|R|)+R-L\),则总移动距离最小为 \(f(L_x,R_x)+f(L_y,R_y)\)。
这里我们规定 \(L\leq 0\leq R\),因为欧捏撒嘛从 \((0,0)\) 开始移动,所以不妨假设有个机器人在 \((0,0)\),方便离散化后限制区间端点。
枚举其中一个区间(下文都规定枚举 \(x\) 轴的区间),令另一个区间极小,就可以获得 \(O(n^3)\) 的做法,而规定枚举顺序使用双指针容易优化到 \(O(n^2)\)。
从大到小枚举 \(R\)(好处在后文),已知上一轮的所有 \(L\) 对应的答案,考虑 \(R\) 左移答案会有什么变化。
先考虑 \(y\) 轴。左移 \(R\) 会释放出一个元素(如果多个元素在同一与 \(y\) 轴平行的直线上都要释放,这里拿一个元素举例子),假设它的 \(y\) 坐标是 \(p_y\),如果 \(p_y\notin [L_y,R_y]\),那么区间会扩张。具体的,应该是进行 \(L_y\leftarrow \min(L_y,p_y)\),\(R_y\leftarrow \max(R_y,p_y)\),考虑使用吉司机线段树维护。
但由于两个操作是独立的,不好维护,所以转换式子:
这样维护两项,修改的时候都是吉司机线段树经典操作,再维护 \(4\) 个区间答案,分别依赖于 \(A'\) 最(次)小、 \(B'\) 最(次)小,修改的时候把依赖于它的答案加上增量即可,这里注意区间答案的合并比较特殊。
再考虑 \(x\) 轴,\([L_x,R_x]\) 固定,把 \(f(L_y,R_y)\) 视作关于 \(L_x\) 的函数,写作 \(F_{R_{x}}(L_x)\)。
对第一项分类讨论容易得出答案应该分两段,查询两次一次查 \(-L\) 一次查 \(-2L\),可以把上面说的四个区间答案维护两次,总时间复杂度 \(O(n\log^2 n)\)。
没明白怎么维护的看代码即可,细节很多,不一一文字叙述。
AC code
#include <bits/stdc++.h>
#define int int64_t
//#define int __int128
//#define MOD (1000000007)
//#define eps (1e-6)
#define endl '\n'
#define debug_endl cout<<endl;
#define debug cout<<"debug"<<endl;
using namespace std;
const int MAXN=1e5+10;
const int INF=4e18;
int ax[MAXN],ay[MAXN];
int vx[MAXN],lx;
struct Segment_Beats{
#define lc (p<<1)
#define rc (p<<1|1)
struct Node{
int ans1[2][2],ans2[2][2];//-L 0:依赖最小,1:依赖非最小
int lans1[2][2],lans2[2][2];//-2L
int a_min[2],a_add;//|L|的最小,次小
int b_min[2],b_add;//|R|的最小,次小
};
Node tr[MAXN<<2];
inline void update_node(int p,int ka,int kb){
if (ka != 0) {
tr[p].a_min[0] += ka;
tr[p].a_add += ka;
for (int j = 0; j <= 1; ++j) {
if (tr[p].ans1[0][j] != INF) tr[p].ans1[0][j] += 2 * ka;
if (tr[p].ans2[0][j] != INF) tr[p].ans2[0][j] += ka;
if (tr[p].lans1[0][j] != INF) tr[p].lans1[0][j] += 2 * ka;
if (tr[p].lans2[0][j] != INF) tr[p].lans2[0][j] += ka;
}
}
if (kb != 0) {
tr[p].b_min[0] += kb;
tr[p].b_add += kb;
for (int i = 0; i <= 1; ++i) {
if (tr[p].ans1[i][0] != INF) tr[p].ans1[i][0] += kb;
if (tr[p].ans2[i][0] != INF) tr[p].ans2[i][0] += 2 * kb;
if (tr[p].lans1[i][0] != INF) tr[p].lans1[i][0] += kb;
if (tr[p].lans2[i][0] != INF) tr[p].lans2[i][0] += 2 * kb;
}
}
}
inline void push_down(int p,int l,int r){
if(l<r&&(tr[p].a_add||tr[p].b_add)){
int mina=min(tr[lc].a_min[0],tr[rc].a_min[0]),minb=min(tr[lc].b_min[0],tr[rc].b_min[0]);
if(tr[lc].a_min[0]==mina&&tr[lc].b_min[0]==minb){
update_node(lc,tr[p].a_add,tr[p].b_add);
}else if(tr[lc].a_min[0]==mina){
update_node(lc,tr[p].a_add,0);
}else if(tr[lc].b_min[0]==minb){
update_node(lc,0,tr[p].b_add);
}
if(tr[rc].a_min[0]==mina&&tr[rc].b_min[0]==minb){
update_node(rc,tr[p].a_add,tr[p].b_add);
}else if(tr[rc].a_min[0]==mina){
update_node(rc,tr[p].a_add,0);
}else if(tr[rc].b_min[0]==minb){
update_node(rc,0,tr[p].b_add);
}
tr[p].a_add=tr[p].b_add=0;
}
}
inline void push_up(int p){
if(tr[lc].a_min[0]==tr[rc].a_min[0]){
tr[p].a_min[0]=tr[lc].a_min[0];
tr[p].a_min[1]=min(tr[lc].a_min[1],tr[rc].a_min[1]);
}else if(tr[lc].a_min[0]<tr[rc].a_min[0]){
tr[p].a_min[0]=tr[lc].a_min[0];
tr[p].a_min[1]=min(tr[lc].a_min[1],tr[rc].a_min[0]);
}else{
tr[p].a_min[0]=tr[rc].a_min[0];
tr[p].a_min[1]=min(tr[lc].a_min[0],tr[rc].a_min[1]);
}
if(tr[lc].b_min[0]==tr[rc].b_min[0]){
tr[p].b_min[0]=tr[lc].b_min[0];
tr[p].b_min[1]=min(tr[lc].b_min[1],tr[rc].b_min[1]);
}else if(tr[lc].b_min[0]<tr[rc].b_min[0]){
tr[p].b_min[0]=tr[lc].b_min[0];
tr[p].b_min[1]=min(tr[lc].b_min[1],tr[rc].b_min[0]);
}else{
tr[p].b_min[0]=tr[rc].b_min[0];
tr[p].b_min[1]=min(tr[lc].b_min[0],tr[rc].b_min[1]);
}
for(int c1=0;c1<=1;++c1) for(int c2=0;c2<=1;++c2) tr[p].ans1[c1][c2]=tr[p].ans2[c1][c2]=tr[p].lans1[c1][c2]=tr[p].lans2[c1][c2]=INF;
for(int c1=0;c1<=1;++c1){
for(int c2=0;c2<=1;++c2){
int cu1=(tr[lc].a_min[0]==tr[p].a_min[0]&&c1==0)?0:1;
int cu2=(tr[lc].b_min[0]==tr[p].b_min[0]&&c2==0)?0:1;
tr[p].ans1[cu1][cu2]=min(tr[p].ans1[cu1][cu2],tr[lc].ans1[c1][c2]);
tr[p].ans2[cu1][cu2]=min(tr[p].ans2[cu1][cu2],tr[lc].ans2[c1][c2]);
tr[p].lans1[cu1][cu2]=min(tr[p].lans1[cu1][cu2],tr[lc].lans1[c1][c2]);
tr[p].lans2[cu1][cu2]=min(tr[p].lans2[cu1][cu2],tr[lc].lans2[c1][c2]);
cu1=(tr[rc].a_min[0]==tr[p].a_min[0]&&c1==0)?0:1;
cu2=(tr[rc].b_min[0]==tr[p].b_min[0]&&c2==0)?0:1;
tr[p].ans1[cu1][cu2]=min(tr[p].ans1[cu1][cu2],tr[rc].ans1[c1][c2]);
tr[p].ans2[cu1][cu2]=min(tr[p].ans2[cu1][cu2],tr[rc].ans2[c1][c2]);
tr[p].lans1[cu1][cu2]=min(tr[p].lans1[cu1][cu2],tr[rc].lans1[c1][c2]);
tr[p].lans2[cu1][cu2]=min(tr[p].lans2[cu1][cu2],tr[rc].lans2[c1][c2]);
}
}
}
void build(int p,int l,int r,int *A,int *B){
tr[p].a_add=tr[p].b_add=0;
if(l==r){
tr[p].ans1[0][0]=2*A[l]+B[l]-vx[l];
tr[p].ans2[0][0]=A[l]+2*B[l]-vx[l];
tr[p].lans1[0][0]=2*A[l]+B[l]-vx[l]*2;
tr[p].lans2[0][0]=A[l]+2*B[l]-vx[l]*2;
tr[p].a_min[1]=tr[p].b_min[1]=INF;
tr[p].ans1[0][1]=tr[p].ans1[1][0]=tr[p].ans1[1][1]=tr[p].ans2[0][1]=tr[p].ans2[1][0]=tr[p].ans2[1][1]=INF;
tr[p].lans1[0][1]=tr[p].lans1[1][0]=tr[p].lans1[1][1]=tr[p].lans2[0][1]=tr[p].lans2[1][0]=tr[p].lans2[1][1]=INF;
tr[p].a_min[0]=A[l];
tr[p].b_min[0]=B[l];
tr[p].a_add=tr[p].b_add=0;
return ;
}
int mid=(l+r)>>1;
build(lc,l,mid,A,B),build(rc,mid+1,r,A,B);
push_up(p);
}
void modify_A(int p,int l,int r,int L,int R,int k){
if(tr[p].a_min[0]>=k) return ;
if(l>=L&&r<=R&&tr[p].a_min[1]>k){
update_node(p,k-tr[p].a_min[0],0);
return ;
}
push_down(p,l,r);
int mid=(l+r)>>1;
if(L<=mid) modify_A(lc,l,mid,L,R,k);
if(R>mid) modify_A(rc,mid+1,r,L,R,k);
push_up(p);
}
void modify_B(int p,int l,int r,int L,int R,int k){
if(tr[p].b_min[0]>=k) return ;
if(l>=L&&r<=R&&tr[p].b_min[1]>k){
update_node(p,0,k-tr[p].b_min[0]);
return ;
}
push_down(p,l,r);
int mid=(l+r)>>1;
if(L<=mid) modify_B(lc,l,mid,L,R,k);
if(R>mid) modify_B(rc,mid+1,r,L,R,k);
push_up(p);
}
int query1(int p,int l,int r,int L,int R){
if(L>R) return INF;//long long要防爆哦
if(l>=L&&r<=R)return min(min(min(tr[p].ans1[0][0],tr[p].ans2[0][0]),min(tr[p].ans1[0][1],tr[p].ans2[0][1])),
min(min(tr[p].ans1[1][0],tr[p].ans2[1][0]),min(tr[p].ans1[1][1],tr[p].ans2[1][1])));
int mid=(l+r)>>1;
int res=INF;
push_down(p,l,r);
if(L<=mid) res=min(res,query1(lc,l,mid,L,R));
if(R>mid) res=min(res,query1(rc,mid+1,r,L,R));
return res;
}
int query2(int p,int l,int r,int L,int R){
if(L>R) return INF;
if(l>=L&&r<=R)return min(min(min(tr[p].lans1[0][0],tr[p].lans2[0][0]),min(tr[p].lans1[0][1],tr[p].lans2[0][1])),
min(min(tr[p].lans1[1][0],tr[p].lans2[1][0]),min(tr[p].lans1[1][1],tr[p].lans2[1][1])));
int mid=(l+r)>>1;
int res=INF;
push_down(p,l,r);
if(L<=mid) res=min(res,query2(lc,l,mid,L,R));
if(R>mid) res=min(res,query2(rc,mid+1,r,L,R));
return res;
}
#undef lc
#undef rc
};
int T,n;
int mapy[MAXN];
int ans,yl[MAXN],yr[MAXN],zeroL,zeroR;
pair<int,int> vy[MAXN];
Segment_Beats tr;
bitset<MAXN> b;
vector<int> tx[MAXN];
void init(){
b.reset();
for(int i=1;i<=n+1;++i) tx[i].clear();
}
inline int f(int L,int R,pair<int,int> *a){
if(L>R) return 0;
return min(abs(a[R].first),abs(a[L].first))+a[R].first-a[L].first;
}
inline int f(int L,int R,int *a){
if(L>R) return 0;
return min(abs(a[R]),abs(a[L]))+a[R]-a[L];
}
signed main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n;
init();
bool flag=true;
for(int i=1;i<=n;++i){
cin>>ax[i]>>ay[i];
if(ax[i]==0&&ay[i]==0) flag=false;
}
if(flag) ++n,ax[n]=0,ay[n]=0;//假想敌(0,0)
for(int i=1;i<=n;++i){
vx[i]=ax[i];
vy[i]={ay[i],i};
}
sort(vx+1,vx+n+1);
sort(vy+1,vy+n+1);
lx=unique(vx+1,vx+n+1)-vx-1;
for(int i=1;i<=n;++i){
int idx=lower_bound(vx+1,vx+lx+1,ax[i])-vx;
tx[idx].emplace_back(i);//离散化后挂载同一x坐标的
idx=lower_bound(vy+1,vy+n+1,make_pair(ay[i],i))-vy;
mapy[i]=idx;
}
zeroL=zeroR=lower_bound(vx+1,vx+lx+1,0)-vx;
ans=f(1,n,vy);//ay满
int l=1,r=n;
for(int L=lx;L>=1;--L){
for(int idx:tx[L]) b[mapy[idx]]=true;
while(l<r&&b[l]&&vy[l+1].first<=0)++l;
while(l<r&&b[r]&&vy[r-1].first>=0)--r;
if(L<=zeroL){
yl[L]=-vy[l].first,yr[L]=vy[r].first;
ans=min(ans,f(l,r,vy)+f(L,lx,vx));
}
}
tr.build(1,1,zeroL,yl,yr);
for(int R=lx-1;R>=zeroR;--R){
for(int idx:tx[R+1]){
if(ay[idx]<0) tr.modify_A(1,1,zeroL,1,zeroL,-ay[idx]);
else if(ay[idx]>0) tr.modify_B(1,1,zeroL,1,zeroL,ay[idx]);
}
int mid=lower_bound(vx+1,vx+lx+1,-vx[R])-vx;
ans=min(ans,min(tr.query1(1,1,zeroL,1,mid-1)+vx[R]*2,tr.query2(1,1,zeroL,mid,zeroL)+vx[R]));
}
cout<<ans<<endl;
}
return 0;
}

浙公网安备 33010602011771号