ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【ARC073D】Many Moves

2021-09-03 22:32:39  阅读:217  来源: 互联网

标签:pre ARC073D int Many ll pos tag Moves define


传送门

我竟然可以独立做出远古ARC的压轴题。我记得上一次做四题 ARC D 还是一道Hall定理+扫描线的神题。

分析:

首先你发现,假设我们已经处理完了前 \(i\) 个询问,则必须有一个棋子在 \(q_{i}\) 的位置。所以我们只关注另外一个棋子的位置,设 \(f_{i,j}\) 是前 \(i\) 轮,另外一个棋子在 \(j\) 位置的最小答案,我们考虑 \(f\) 的转移:

  • 移动在 \(q_i\) 位置上的棋子:\(f_{i+1,j}=f_{i,j}+|q_{i+1}-q_{i}|\)。

  • 移动在 \(j\) 位置上的棋子:\(f_{i+1,q_i}=\min\{f_{i,j}+|q_{i+1}-j|\}\)。

考虑特殊考虑初始位置,或者说,考虑前 \(i\) 轮仅动了第一个或者第二个棋子的情况。我们设 \(pre_1(i)\) 是仅移动第一个棋子完成前 \(i\) 个要求的答案,\(pre_2(i)\) 是第二个。那么有:

  • \(f_{i+1,q_i}=pre_1(i)+|q_{i+1}-b|\)。

  • \(f_{i+1,q_i}=pre_2(i)+|q_{i+1}-a|\)。

最后答案应为 \(\min\{f(Q,i)\}\),然后和 \(pre_1(Q)\) 和 \(pre_2(Q)\) 取 \(\min\)。

现在这个东西是 \(O(nQ)\) 的,考虑线段树优化 DP:

对于第一种操作是一个区间加的过程。

第二种操作我们对绝对值分讨,则要求区间里 \(f_{i,j}-j\) 和 \(f_{i,j}+j\) 的最小值,可以结合操作 \(1\) 直接维护。

后面的所有操作都是单点修改,可以每次暴力 \(O(\log n)\) 找点去修改,不影响上面的懒标记过程。

所以总复杂度为 \(O(n\log n)\)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define op(x) ((x&1)?x+1:x-1)
#define odd(x) (x&1)
#define even(x) (!odd(x))
#define lc(x) (x<<1)
#define rc(x) (lc(x)|1)
#define lowbit(x) (x&-x)
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define next Cry_For_theMoon
#define il inline
#define pb(x) push_back(x)
#define is(x) insert(x)
#define sit set<int>::iterator
#define mapit map<int,int>::iterator
#define pi pair<int,int>
#define ppi pair<int,pi>
#define pp pair<pi,pi>
#define fr first
#define se second
#define vit vector<int>::iterator
#define mp(x,y) make_pair(x,y)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double db;
using namespace std;
const ll MAXN=2e5+10,INF=1e15;
ll n,q,a,b,pos[MAXN],ans=INF;
ll pre[2][MAXN];
struct SegmenTree{
	ll val[MAXN<<2],tag[MAXN<<2];
	ll minn1[MAXN<<2],minn2[MAXN<<2];
	void pushup(int x){
		minn1[x]=min(minn1[lc(x)],minn1[rc(x)]);
		minn2[x]=min(minn2[lc(x)],minn2[rc(x)]);
	}
	void pushdown(int x,int l,int r){
		int mid=(l+r)>>1;
		if(l==mid){val[lc(x)]+=tag[x];}
		if(mid+1==r){val[rc(x)]+=tag[x];} 
		minn1[lc(x)]+=tag[x];minn2[lc(x)]+=tag[x];
		minn1[rc(x)]+=tag[x];minn2[rc(x)]+=tag[x];
		tag[lc(x)]+=tag[x];tag[rc(x)]+=tag[x];tag[x]=0;
	} 
	void build(int x,int l,int r){
		if(l==r){
			val[x]=INF;
			minn1[x]=minn2[x]=INF;
			return;
		}
		int mid=(l+r)>>1;
		build(lc(x),l,mid);build(rc(x),mid+1,r);
		pushup(x);
	}
	void update(int x,int l,int r,int ql,int qr,ll val1){
		if(ql<=l && qr>=r){
			if(l==r){val[x]+=val1;}
			minn1[x]+=val1;minn2[x]+=val1;
			tag[x]+=val1;
			return;
		}
		pushdown(x,l,r);
		int mid=(l+r)>>1;
		if(ql<=mid)update(lc(x),l,mid,ql,qr,val1);
		if(qr>mid)update(rc(x),mid+1,r,ql,qr,val1);
		pushup(x); 
	}
	void modify(int x,int l,int r,int pos,ll num){
		if(l==r){
			val[x]=min(val[x],num);
			minn1[x]=val[x]-l;
			minn2[x]=val[x]+l;
			return;
		}
		pushdown(x,l,r);
		int mid=(l+r)>>1;
		if(pos<=mid)modify(lc(x),l,mid,pos,num);
		else modify(rc(x),mid+1,r,pos,num); 
		pushup(x); 
	}
	ll query(int x,int l,int r,int pos){
		if(l==r)return val[x];
		pushdown(x,l,r);
		int mid=(l+r)>>1;
		ll ans;
		if(pos<=mid)ans=query(lc(x),l,mid,pos);
		else ans=query(rc(x),mid+1,r,pos);
		pushup(x);return ans;
	}
	ll query1(int x,int l,int r,int ql,int qr){
		if(ql<=l && qr>=r)return minn1[x];
		pushdown(x,l,r);
		int mid=(l+r)>>1;ll ret=INF;
		if(ql<=mid)ret=min(ret,query1(lc(x),l,mid,ql,qr));
		if(qr>mid)ret=min(ret,query1(rc(x),mid+1,r,ql,qr));
		return ret;
	}
	ll query2(int x,int l,int r,int ql,int qr){
		if(ql<=l && qr>=r)return minn2[x];
		pushdown(x,l,r);
		int mid=(l+r)>>1;ll ret=INF;
		if(ql<=mid)ret=min(ret,query2(lc(x),l,mid,ql,qr));
		if(qr>mid)ret=min(ret,query2(rc(x),mid+1,r,ql,qr));
		return ret;
	}
}tree;
int main(){
	cin>>n>>q>>a>>b;
	rep(i,1,q){
		cin>>pos[i];
	}
	rep(i,1,q){
		if(i==1){
			pre[0][i]=abs(a-pos[1]);
			pre[1][i]=abs(b-pos[1]);
		}else{
			pre[0][i]=pre[0][i-1]+abs(pos[i-1]-pos[i]);
			pre[1][i]=pre[1][i-1]+abs(pos[i-1]-pos[i]);
		}
	}
	tree.build(1,1,n);
	rep(i,2,q){
		ll tmp=INF;
		tmp=min(tmp,pos[i]+tree.query1(1,1,n,1,pos[i]));
		if(pos[i]!=n){
			tmp=min(tmp,tree.query2(1,1,n,pos[i]+1,n)-pos[i]);
		}
		tree.update(1,1,n,1,n,abs(pos[i]-pos[i-1]));
		tree.modify(1,1,n,pos[i-1],tmp);
		tree.modify(1,1,n,pos[i-1],pre[0][i-1]+abs(pos[i]-b));
		tree.modify(1,1,n,pos[i-1],pre[1][i-1]+abs(pos[i]-a));
	}
	ans=min(ans,pre[0][q]);
	ans=min(ans,pre[1][q]);
	rep(i,1,n){
		ans=min(ans,tree.query(1,1,n,i));
	}
	cout<<ans<<endl;
	return 0;
}

标签:pre,ARC073D,int,Many,ll,pos,tag,Moves,define
来源: https://www.cnblogs.com/Cry-For-theMoon/p/15225246.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有