首页 > 其他分享 >JOISC2017j 誘拐 2 (Abduction 2)

JOISC2017j 誘拐 2 (Abduction 2)

时间:2022-12-14 08:33:05浏览次数:62  
标签:return int ans1 ans2 dfs ind Abduction 誘拐 JOISC2017j

\(\mathcal Link\)

做法一

现考虑一个人的情况。设 \(f_{i,j,0/1}\) 表示从 \((i,j)\) 开始沿横/竖方向走的最大距离。

走到下一个位置相当于在其中一个数组中向左/右找第一个大于某值的位置。可以用 ST 表或线段树解决。

若使用线段树解决,考虑将其分为 \(\mathcal O(\log n)\) 个区间,并找到最左/右的可能区间递归进去,复杂度仍为 \(O(\log n)\)。

发现由于所需的状态实际上不会很多,所以可以使用记忆化,然后就过了。复杂度 \(\mathcal O(玄学)\)。

#include <map>
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
char buf[1<<14],*p1=buf,*p2=buf;
#define GetC() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++)
struct Ios{}io;
template <typename _tp>
Ios &operator >>(Ios &in,_tp &x){
    x=0;int w=0;char c=GetC();
    for(;!isdigit(c);w|=c=='-',c=GetC());
    for(;isdigit(c);x=x*10+(c^'0'),c=GetC());
    if(w) x=-x;
    return in;
}
using ll=long long;
const int N=5e4+5;
int a[N],b[N];
struct Seg{
	int mx[N<<2];
	#define lc(p) ((p)<<1)
	#define rc(p) ((p)<<1|1)
	void build(int p,int l,int r,int a[]){
		if(l==r){
			mx[p]=a[l];
			return ;
		}
		int mid=(l+r)>>1;
		build(lc(p),l,mid,a);
		build(rc(p),mid+1,r,a);
		mx[p]=max(mx[lc(p)],mx[rc(p)]);
	}
	int queryL(int p,int l,int r,int x,int v){
		if(l>=x||mx[p]<=v) return -1;
		if(l==r) return l;
		int mid=(l+r)>>1;
		int ind=queryL(rc(p),mid+1,r,x,v);
		if(ind!=-1) return ind;
		return queryL(lc(p),l,mid,x,v);
	}
	int queryR(int p,int l,int r,int x,int v){
		if(r<=x||mx[p]<=v) return -1;
		if(l==r) return l;
		int mid=(l+r)>>1;
		int ind=queryR(lc(p),l,mid,x,v);
		if(ind!=-1) return ind;
		return queryR(rc(p),mid+1,r,x,v);
	}
	#undef lc
	#undef rc
}tr1,tr2;
map<int,ll> mp[N][2];
int n,m;
ll dfs(int x,int y,int d){
	if(mp[x][d].count(y)) return mp[x][d][y];
	if(d==1){
		ll ans1=tr1.queryL(1,1,n,x,b[y]),ans2=tr1.queryR(1,1,n,x,b[y]);
		if(ans1==-1) ans1=x-1;
		else ans1=(x-ans1)+dfs(ans1,y,d^1);
		if(ans2==-1) ans2=n-x;
		else ans2=(ans2-x)+dfs(ans2,y,d^1);
		return mp[x][d][y]=max(ans1,ans2);
	}
	else{
		ll ans1=tr2.queryL(1,1,m,y,a[x]),ans2=tr2.queryR(1,1,m,y,a[x]);
		if(ans1==-1) ans1=y-1;
		else ans1=(y-ans1)+dfs(x,ans1,d^1);
		if(ans2==-1) ans2=m-y;
		else ans2=(ans2-y)+dfs(x,ans2,d^1);
		return mp[x][d][y]=max(ans1,ans2);
	}
}
signed main(){
	int q;
	io>>n>>m>>q;
	for(int i=1;i<=n;++i) io>>a[i];
	for(int i=1;i<=m;++i) io>>b[i];
	tr1.build(1,1,n,a);tr2.build(1,1,m,b);
	for(int i=1;i<=q;++i){
		int x,y;io>>x>>y;
		printf("%lld\n",max(dfs(x,y,0),dfs(x,y,1)));
	}
    return 0; 
}

做法二(推荐)

考虑分治。对于一个矩形,在其最外侧加上一层权值为 \(-1\) 的边框(抵消走出的贡献)。则每次考虑选出边权最大的边,其只能一直直走,若其两端与外边框所交位置的答案分别为 \(a,b\),则编号为 \(x\) 的点的答案为 \(\max(a+x-l,b+r-x)\),然后以该线为界,分成左右矩形,然后选择一边递归即可。注意到我们只需要记录好 \(\max\) 函数的参数即可。用 ST 表找最大值,复杂度 \(\mathcal O(n\log n+m\log m+q(n+m))\)

标签:return,int,ans1,ans2,dfs,ind,Abduction,誘拐,JOISC2017j
From: https://www.cnblogs.com/pref-ctrl27/p/16976984.html

相关文章