#include<bits/stdc++.h>

#define x first

#define y second

#define pb push_back

using namespace std;

typedef long long INT;

typedef vector<int> VI;

typedef pair<int, int> pii;

template<typename T, typename U> inline void smin(T &a, const U &b) {if(a>b) a=b;}

template<typename T, typename U> inline void smax(T &a, const U &b) {if(a<b) a=b;}

template <class T> inline void gn(T &x) {char c, sg=0; while(c=getchar(), (c>'9' || c<'0') && c!='-'); for((c=='-' ? sg=1, c=getchar() : 0), x=0; c>='0' && c<='9'; c=getchar()) x=(x<<1)+(x<<3)+c-'0'; if(sg) x=-x;}

template <class T1, class T2> inline void gn(T1 &x1, T2 &x2) {gn(x1), gn(x2);}

int power(int a, int b, int m, int ans=1){for (; b; b>>=1, a=1LL*a*a%m) if (b&1) ans=1LL*ans*a%m; return ans;}

#define NN 100100

pii p[NN<<1];

#define MM 5000000

#define mid (L+R>>1)

int sum[MM], ls[MM], rs[MM];

int root[NN];

int cur;

void push_up(int u){

	sum[u]=sum[ls[u]]+sum[rs[u]];

}

int build(int L, int R){

	int u=cur++;

	if(L+1==R){

		return u;

	}

	ls[u]=build(L, mid);

	rs[u]=build(mid, R);

	return u;

}

int clone(int u){

	int ans=cur++;

	ls[ans]=ls[u];

	rs[ans]=rs[u];

	sum[ans]=sum[u];

	return ans;

}

int update(int u, int L, int R, int p){

	if(p<L || R<=p) return u;

	int ans=clone(u);

	if(L+1==R){

		sum[ans]++;

		return ans;

	}

	ls[ans]=update(ls[u], L, mid, p);

	rs[ans]=update(rs[u], mid, R, p);

	push_up(ans);

	return ans;

}

int calc(int st, int ed, int L, int R, int l, int r){

	if(r<=L || R<=l) return 0;

	if(l<=L && R<=r) return sum[st]-sum[ed];

	return calc(ls[st], ls[ed], L, mid, l, r)||calc(rs[st], rs[ed], mid, R, l, r);

}

VI X, Y;

int calc(int x1, int y1, int x2, int y2){

	x1=lower_bound(X.begin(), X.end(), x1)-X.begin();

	x2=upper_bound(X.begin(), X.end(), x2)-X.begin();

	y1=lower_bound(Y.begin(), Y.end(), y1)-Y.begin();

	y2=upper_bound(Y.begin(), Y.end(), y2)-Y.begin();

	return calc(root[x1], root[x2], 0, Y.size(), y1, y2);

}

int id[NN], dis[NN];

int main(){

#ifndef ONLINE_JUDGE

	freopen("in.in", "r", stdin);

	freopen("out.out", "w", stdout);

#endif

	int n, k;

	cin >> n >> k;

	for(int i=0, x, y; i<n+k; i++){

		gn(x, y);

		p[i]=pii(x+y, x-y);

	}

	pii *q=p+n;

	for(int i=0; i<k; i++){

		X.pb(q[i].x);

		Y.pb(q[i].y);

	}

	sort(X.begin(), X.end());

	X.resize(unique(X.begin(), X.end())-X.begin());

	sort(Y.begin(), Y.end());

	Y.resize(unique(Y.begin(), Y.end())-Y.begin());

	for(int i=0; i<k; i++){

		q[i].x=lower_bound(X.begin(), X.end(), q[i].x)-X.begin();

		q[i].y=lower_bound(Y.begin(), Y.end(), q[i].y)-Y.begin();

	}

	if(k){

		sort(q, q+k, [](pii a, pii b){return a.x>b.x;});

		root[X.size()]=build(0, Y.size());

		for(int i=0, j=0; i<X.size(); i++){

			root[i]=root[i+1];

			while(j<k && q[j].x==i){

				root[i]=update(root[i], 1, Y.size()+1, q[j].y);

				j++;

			}

		}

		for(int i=0; i<n; i++){

			int st=-1, ed=1e9, md;

			while(ed-st>1){

				md=st+ed>>1;

				if(calc(p[i].x-md, p[i].y-md, p[i].x+md, p[i].y+md)) ed=md;

				else st=md;

			}

			id[i]=i;

			dis[i]=ed;

		}

		sort(id, id+n, [](int a, int b){return dis[a]>dis[b];});

	}

	else for(int i=0; i<n; i++) dis[i]=1e9;

	int st=-1, ed=1e9, md;

	while(ed-st>1){

		md=st+ed>>1;

		int x1=-1e9, y1=-1e9, x2=1e9, y2=1e9;

		int ok=0;

		for(int i=0; i<n; i++){

			int rem=md-dis[id[i]];

			if(k && rem>=0 && calc(x1-rem, y1-rem, x2+rem, y2+rem)){

				ok=1;

				break;

			}

			smax(x1, p[id[i]].x-md);

			smax(y1, p[id[i]].y-md);

			smin(x2, p[id[i]].x+md);

			smin(y2, p[id[i]].y+md);

			if(x1>x2 || y1>y2) break;

		}

		if(ok || x1<=x2 && y1<=y2) ed=md;

		else st=md;

	}

	cout << ed << endl;

	return 0;

}


#include<bits/stdc++.h>

#define inf 0x3f3f3f3f

#define y second

#define x first

using namespace std;

typedef pair<int, int> pii;

typedef pair<pii, int> pi3;

template<typename T, typename U> inline void smin(T &a, const U &b) {if(a>b) a=b;}

template<typename T, typename U> inline void smax(T &a, const U &b) {if(a<b) a=b;}

#define NN 100100

#define MM 400400

int id[NN], LL[MM], RR[MM];

int x[NN], y[NN], xmn[MM], xmx[MM], ymn[MM], ymx[MM];

inline void select(int L, int mid, int R, int* val) {

	R--;

	while(L+1<=R) {

		if(L+1==R) {

			if(val[id[L]]>val[id[R]]) swap(id[L], id[R]);

			return ;

		}

		int S=L+1, X=S+rand()*rand()%(R-L);

		swap(id[L], id[X]);

		if(val[id[L]]>val[id[R]]) swap(id[L], id[R]);

		if(val[id[L]]>val[id[S]]) swap(id[L], id[S]);

		if(val[id[S]]>val[id[R]]) swap(id[S], id[R]);

		int i=L, j=R, p=val[id[S]];

		while(1) {

			while(i<=R && val[id[i]]<=p) i++;

			while(j>=L && val[id[j]]>=p) j--;

			if(i>j) break;

			swap(id[i], id[j]);

		}

		if(mid<=j) R=j;

		else if(mid>=i) L=i;

		else break;

	}

}

inline void build(int u, int L, int R, int dp=0) {

	LL[u]=L, RR[u]=R;

	if(L+1==R) {

		xmn[u]=xmx[u]=x[id[L]];

		ymn[u]=ymx[u]=y[id[L]];

		return ;

	}

	int ls=u<<1, rs=ls|1, mid=L+R>>1;

	if(dp) select(L, mid, R, x);

	else select(L, mid, R, y);

	dp^=1;

	build(ls, L, mid, dp);

	build(rs, mid, R, dp);

	xmn[u]=min(xmn[ls], xmn[rs]), xmx[u]=max(xmx[ls], xmx[rs]);

	ymn[u]=min(ymn[ls], ymn[rs]), ymx[u]=max(ymx[ls], ymx[rs]);

}

int ax, ay, bx, by;

inline bool calc(int u) {

	if(xmn[u]>bx || xmx[u]<ax || ymn[u]>by || ymx[u]<ay) return false;

	if(ax<=xmn[u] && xmx[u]<=bx && ay<=ymn[u] && ymx[u]<=by) return true;

	if(LL[u]+1==RR[u]) return false;

	int ls=u<<1;

	if(calc(ls)) return true;

	return calc(ls|1);

}

pi3 p[NN];

int n, m;

inline bool can(int T) {

	ax=ay=-inf, bx=by=inf;

	for(int i=0; i<n; i++) {

		if(ax<=bx && ay<=by) {

			if(!m) continue;

			if(p[i].y<=T) {

				int d=T-p[i].y;

				ax-=d, bx+=d;

				ay-=d, by+=d;

				if(calc(1)) return true;

				ax+=d, bx-=d;

				ay+=d, by-=d;

			}

		}

		else return false;

		int x=p[i].x.x, y=p[i].x.y;

		smax(ax, x-T), smin(bx, x+T);

		smax(ay, y-T), smin(by, y+T);

	}

	return ax<=bx && ay<=by;

}

main() {

#ifndef	ONLINE_JUDGE

	freopen("in.in", "r", stdin);

	freopen("out.out", "w", stdout);

#endif

	srand(time(0));

	scanf("%d %d", &n, &m);

	if(n==1) return puts("0");

	for(int i=0, x, y; i<n; i++) {

		scanf("%d %d", &x, &y);

		p[i]=pi3(pii(x-y, x+y), 0);

	}

	for(int i=0, x, y; i<m; i++) {

		::x[i]=x-y;

		::y[i]=x+y;

		id[i]=i;

	}

	if(m) build(1, 0, m);

	for(int i=0, x, y; i<n; i++) {

		x=p[i].x.x, y=p[i].x.y;

		int st=-1, ed=inf;

		while(st+1<ed) {

			int md=st+ed>>1;

			ax=x-md, bx=x+md, ay=y-md, by=y+md;

			if(m && calc(1)) ed=md;

			else st=md;

		}

		p[i].y=ed;

	}

	sort(p, p+n, [](pi3 a, pi3 b) {return a.y>b.y;});

	int st=-1, ed=inf;

	while(st+1<ed) {

		int md=st+ed>>1;

		if(can(md)) ed=md;

		else st=md;

	}

	printf("%d", ed);

}


#include<bits/stdc++.h>

#define x first

#define y second

#define pb push_back

using namespace std;

typedef long long INT;

typedef vector<int> VI;

typedef pair<int, int> pii;

template<typename T, typename U> inline void smin(T &a, const U &b) {if(a>b) a=b;}

template<typename T, typename U> inline void smax(T &a, const U &b) {if(a<b) a=b;}

template <class T> inline void gn(T &x) {char c, sg=0; while(c=getchar(), (c>'9' || c<'0') && c!='-'); for((c=='-' ? sg=1, c=getchar() : 0), x=0; c>='0' && c<='9'; c=getchar()) x=(x<<1)+(x<<3)+c-'0'; if(sg) x=-x;}

template <class T1, class T2> inline void gn(T1 &x1, T2 &x2) {gn(x1), gn(x2);}

int power(int a, int b, int m, int ans=1){for (; b; b>>=1, a=1LL*a*a%m) if (b&1) ans=1LL*ans*a%m; return ans;}

#define NN 100100

pii p[NN<<1];

#define MM 5000000

#define mid (L+R>>1)

int sum[MM], ls[MM], rs[MM];

int root[NN];

int cur;

void push_up(int u){

	sum[u]=sum[ls[u]]+sum[rs[u]];

}

int build(int L, int R){

	int u=cur++;

	if(L+1==R){

		return u;

	}

	ls[u]=build(L, mid);

	rs[u]=build(mid, R);

	return u;

}

int clone(int u){

	int ans=cur++;

	ls[ans]=ls[u];

	rs[ans]=rs[u];

	sum[ans]=sum[u];

	return ans;

}

int update(int u, int L, int R, int p){

	if(p<L || R<=p) return u;

	int ans=clone(u);

	if(L+1==R){

		sum[ans]++;

		return ans;

	}

	ls[ans]=update(ls[u], L, mid, p);

	rs[ans]=update(rs[u], mid, R, p);

	push_up(ans);

	return ans;

}

int calc(int st, int ed, int L, int R, int l, int r){

	if(r<=L || R<=l) return 0;

	if(l<=L && R<=r) return sum[st]-sum[ed];

	return calc(ls[st], ls[ed], L, mid, l, r)||calc(rs[st], rs[ed], mid, R, l, r);

}

VI X, Y;

int calc(int x1, int y1, int x2, int y2){

	x1=lower_bound(X.begin(), X.end(), x1)-X.begin();

	x2=upper_bound(X.begin(), X.end(), x2)-X.begin();

	y1=lower_bound(Y.begin(), Y.end(), y1)-Y.begin();

	y2=upper_bound(Y.begin(), Y.end(), y2)-Y.begin();

	return calc(root[x1], root[x2], 0, Y.size(), y1, y2);

}

int id[NN], dis[NN];

int main(){

#ifndef ONLINE_JUDGE

	freopen("in.in", "r", stdin);

	freopen("out.out", "w", stdout);

#endif

	int n, k;

	cin >> n >> k;

	for(int i=0, x, y; i<n+k; i++){

		gn(x, y);

		p[i]=pii(x+y, x-y);

	}

	pii *q=p+n;

	for(int i=0; i<k; i++){

		X.pb(q[i].x);

		Y.pb(q[i].y);

	}

	sort(X.begin(), X.end());

	X.resize(unique(X.begin(), X.end())-X.begin());

	sort(Y.begin(), Y.end());

	Y.resize(unique(Y.begin(), Y.end())-Y.begin());

	for(int i=0; i<k; i++){

		q[i].x=lower_bound(X.begin(), X.end(), q[i].x)-X.begin();

		q[i].y=lower_bound(Y.begin(), Y.end(), q[i].y)-Y.begin();

	}

	for(int i=0; i<n; i++) id[i]=i;

	if(k){

		sort(q, q+k, [](pii a, pii b){return a.x>b.x;});

		root[X.size()]=build(0, Y.size());

		for(int i=0, j=0; i<X.size(); i++){

			root[i]=root[i+1];

			while(j<k && q[j].x==i){

				root[i]=update(root[i], 0, Y.size(), q[j].y);

				j++;

			}

		}

		for(int i=0; i<n; i++){

			int st=-1, ed=1e9, md;

			while(ed-st>1){

				md=st+ed>>1;

				if(calc(p[i].x-md, p[i].y-md, p[i].x+md, p[i].y+md)) ed=md;

				else st=md;

			}

			dis[i]=ed;

		}

		sort(id, id+n, [](int a, int b){return dis[a]>dis[b];});

	}

	else for(int i=0; i<n; i++) dis[i]=1e9;

	int st=-1, ed=1e9, md;

	while(ed-st>1){

		md=st+ed>>1;

		int x1=-1e9, y1=-1e9, x2=1e9, y2=1e9;

		int ok=0;

		for(int i=0; i<n; i++){

			if(k){

				int rem=md-dis[id[i]];

				if(rem>=0 && calc(x1-rem, y1-rem, x2+rem, y2+rem)){

					ok=1;

					break;

				}

			}

			smax(x1, p[id[i]].x-md);

			smax(y1, p[id[i]].y-md);

			smin(x2, p[id[i]].x+md);

			smin(y2, p[id[i]].y+md);

			if(x1>x2 || y1>y2) break;

		}

		if(ok || x1<=x2 && y1<=y2) ed=md;

		else st=md;

	}

	cout << ed << endl;

	return 0;

}


#include <bits/stdc++.h>
#define il inline
#define ri register int
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define mid ((l+r)>>1)
#define MAXN 200050
#define MAXM 200000000
#define mod
#define inf 1000000000
#define eps (1e-6)
#define alpha 0.75
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define repd(i, x, y) for(ri i = x; i >= y; --i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ll, int> pli;
typedef pair <int, ll> pil;
typedef pair <ll, ll> pll;
template <typename T> inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <typename T> inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
il void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = x*10+ch-'0', ch = getchar();
	x *= f;
}
int n, k, ccnt, ch[MAXN<<5][2], size[MAXN<<5], tcnt, root[MAXN], b[MAXN];
struct node {
	int x, y, dis;
	bool operator < (const node &a) const {
		return dis < a.dis;
	}
} a[MAXN];
pii v[MAXN];
void copy(int u, int p) {
	rep(i, 0, 1) ch[u][i] = ch[p][i];
	size[u] = size[p];
}
void ins(int &u, int l, int r, int x) {
	int tmp = u; u = ++tcnt, copy(u, tmp);
	++size[u];
	if(l == r) return ;
	if(x <= mid) ins(ch[u][0], l, mid, x);
	else ins(ch[u][1], mid+1, r, x);
}
int query(int u, int l, int r, int tl, int tr) {
	if(!u) return 0;
	if(tl <= l && r <= tr) return size[u];
	int ret = 0;
	if(tl <= mid) ret += query(ch[u][0], l, mid, tl, tr);
	if(mid < tr) ret += query(ch[u][1], mid+1, r, tl, tr);
	return ret;
}
int get(int xl, int xr, int yl, int yr) {
	xl = lower_bound(v+1, v+k+1, mp(xl, -inf))-v, xr = upper_bound(v+1, v+k+1, mp(xr, inf))-v-1;
	yl = lower_bound(b+1, b+ccnt+1, yl)-b, yr = upper_bound(b+1, b+ccnt+1, yr)-b-1;
	return query(root[xr], 1, ccnt, yl, yr)-query(root[xl-1], 1, ccnt, yl, yr);
}
bool check(int tms) {
	int xl = -inf, xr = inf, yl = -inf, yr = inf;
	repd(i, n, 1) {
		if(xl > xr || yl > yr) break;
		int t = tms-a[i].dis;
		if(t >= 0 && get(xl-t, xr+t, yl-t, yr+t)) return 1;
		chkmax(xl, a[i].x-tms), chkmin(xr, a[i].x+tms);
		chkmax(yl, a[i].y-tms), chkmin(yr, a[i].y+tms);
	}
	// cout<<"checking: "<<tms<<endl;
	return xl <= xr && yl <= yr;
}
int main() {
	int x, y;
	read(n), read(k);
	rep(i, 1, n) read(x), read(y), a[i] = node{x+y, y-x, inf};
	rep(i, 1, k) read(x), read(y), v[i] = mp(x+y, y-x), b[i] = v[i].sec;
	sort(v+1, v+k+1), sort(b+1, b+k+1);
	ccnt = unique(b+1, b+k+1)-b-1;
	rep(i, 1, k) v[i].sec = lower_bound(b+1, b+ccnt+1, v[i].sec)-b;
	rep(i, 1, k) root[i] = root[i-1], ins(root[i], 1, ccnt, v[i].sec);
	rep(i, 1, n) {
		int l = 0, r = MAXM*2;
		while(l <= r) {
			if(get(a[i].x-mid, a[i].x+mid, a[i].y-mid, a[i].y+mid))
				a[i].dis = mid, r = mid-1;
			else l = mid+1;
		}
	}
	// rep(i, 1, n) cout<<a[i].dis<<' ';
	// puts("");
	sort(a+1, a+n+1);
	int l = 0, r = MAXM*2, ans;
	while(l <= r) {
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	return 0;
}


#include <bits/stdc++.h>
#define il inline
#define ri register int
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define mid ((l+r)>>1)
#define MAXN 200050
#define MAXM 100000000
#define mod
#define inf 1000000000
#define eps (1e-6)
#define alpha 0.75
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define repd(i, x, y) for(ri i = x; i >= y; --i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ll, int> pli;
typedef pair <int, ll> pil;
typedef pair <ll, ll> pll;
template <typename T> inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <typename T> inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
il void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = x*10+ch-'0', ch = getchar();
	x *= f;
}
int n, k, ch[MAXN<<5][2], size[MAXN<<5], tcnt, root[MAXN];
struct node {
	int x, y, dis;
	bool operator < (const node &a) const {
		return dis < a.dis;
	}
} a[MAXN];
pii v[MAXN];
void copy(int u, int p) {
	rep(i, 0, 1) ch[u][i] = ch[p][i];
	size[u] = size[p];
}
void ins(int &u, int l, int r, int x) {
	int tmp = u; u = ++tcnt, copy(u, tmp);
	++size[u];
	if(l == r) return ;
	if(x <= mid) ins(ch[u][0], l, mid, x);
	else ins(ch[u][1], mid+1, r, x);
}
int query(int u, int l, int r, int tl, int tr) {
	if(!u) return 0;
	if(tl <= l && r <= tr) return size[u];
	int ret = 0;
	if(tl <= mid) ret += query(ch[u][0], l, mid, tl, tr);
	if(mid < tr) ret += query(ch[u][1], mid+1, r, tl, tr);
	return ret;
}
int get(int xl, int xr, int yl, int yr) {
	int L = lower_bound(v+1, v+k+1, mp(xl, -inf))-v, R = upper_bound(v+1, v+k+1, mp(xr, inf))-v-1;
	return query(root[R], -MAXM, MAXM, yl, yr)-query(root[L-1], -MAXM, MAXM, yl, yr);
}
bool check(int tms) {
	if(tms >= a[n].dis) return 1;
	// cout<<"checking: "<<tms<<endl;
	int xl = -1e9, xr = 1e9, yl = -1e9, yr = 1e9;
	int pos = n;
	while(pos && a[pos].dis > tms) {
		chkmax(xl, a[pos].x-tms), chkmin(xr, a[pos].x+tms);
		chkmax(yl, a[pos].y-tms), chkmin(yr, a[pos].y+tms);
		--pos;
	}
	while(pos) {
		if(xl > xr || yl > yr) break;
		int t = tms-a[pos].dis;
		if(t >= 0 && get(xl-t, xr+t, yl-t, yr+t)) {
			// cout<<"success in: "<<pos<<' '<<t<<' '<<xl-t<<' '<<xr+t<<' '<<yl-t<<' '<<yr+t<<endl;
			return 1;
		}
		chkmax(xl, a[pos].x-tms), chkmin(xr, a[pos].x+tms);
		chkmax(yl, a[pos].y-tms), chkmin(yr, a[pos].y+tms);
		--pos;
	}
	// cout<<"checking: "<<tms<<endl;
	return xl <= xr && yl <= yr;
}
int main() {
	int x, y;
	read(n), read(k);
	rep(i, 1, n) read(x), read(y), a[i] = node{x+y, y-x, inf};
	rep(i, 1, k) read(x), read(y), v[i] = mp(x+y, y-x);
	sort(v+1, v+k+1);
	rep(i, 1, k) root[i] = root[i-1], ins(root[i], -MAXM, MAXM, v[i].sec);
	rep(i, 1, n) {
		int l = 0, r = MAXM*2;
		while(l <= r) {
			if(get(a[i].x-mid, a[i].x+mid, a[i].y-mid, a[i].y+mid))
				a[i].dis = mid, r = mid-1;
			else l = mid+1;
		}
	}
	// rep(i, 1, n) cout<<a[i].dis<<' ';
	// puts("");
	sort(a+1, a+n+1);
	int l = 0, r = MAXM*2, ans;
	while(l <= r) {
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	return 0;
}


#include <bits/stdc++.h>
#define il inline
#define ri register int
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define mid ((l+r)>>1)
#define MAXN 100050
#define MAXM 100000000
#define mod
#define inf 1000000000
#define eps (1e-6)
#define alpha 0.75
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define repd(i, x, y) for(ri i = x; i >= y; --i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ll, int> pli;
typedef pair <int, ll> pil;
typedef pair <ll, ll> pll;
template <typename T> inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <typename T> inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
il void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = x*10+ch-'0', ch = getchar();
	x *= f;
}
int n, k, ch[MAXN<<5][2], size[MAXN<<5], tcnt, root[MAXN];
struct node {
	int x, y, dis;
	bool operator < (const node &a) const {
		return dis < a.dis;
	}
} a[MAXN];
pii v[MAXN];
void copy(int u, int p) {
	rep(i, 0, 1) ch[u][i] = ch[p][i];
	size[u] = size[p];
}
void ins(int &u, int l, int r, int x) {
	int tmp = u; u = ++tcnt, copy(u, tmp);
	++size[u];
	if(l == r) return ;
	if(x <= mid) ins(ch[u][0], l, mid, x);
	else ins(ch[u][1], mid+1, r, x);
}
int query(int u, int l, int r, int tl, int tr) {
	if(!u) return 0;
	if(tl <= l && r <= tr) return size[u];
	int ret = 0;
	if(tl <= mid) ret += query(ch[u][0], l, mid, tl, tr);
	if(mid < tr) ret += query(ch[u][1], mid+1, r, tl, tr);
	return ret;
}
int get(int xl, int xr, int yl, int yr) {
	int L = lower_bound(v+1, v+k+1, mp(xl, -inf))-v, R = upper_bound(v+1, v+k+1, mp(xr, inf))-v-1;
	return query(root[R], -MAXM, MAXM, yl, yr)-query(root[L-1], -MAXM, MAXM, yl, yr);
}
bool check(int tms) {
	if(tms >= a[n].dis) return 1;
	// cout<<"checking: "<<tms<<endl;
	int xl = -1e9, xr = 1e9, yl = -1e9, yr = 1e9;
	int pos = n;
	while(pos && a[pos].dis > tms) {
		chkmax(xl, a[pos].x-tms), chkmin(xr, a[pos].x+tms);
		chkmax(yl, a[pos].y-tms), chkmin(yr, a[pos].y+tms);
		--pos;
	}
	while(pos) {
		if(xl > xr || yl > yr) break;
		int t = tms-a[pos].dis;
		if(t >= 0 && get(xl-t, xr+t, yl-t, yr+t)) {
			// cout<<"success in: "<<pos<<' '<<t<<' '<<xl-t<<' '<<xr+t<<' '<<yl-t<<' '<<yr+t<<endl;
			return 1;
		}
		chkmax(xl, a[pos].x-tms), chkmin(xr, a[pos].x+tms);
		chkmax(yl, a[pos].y-tms), chkmin(yr, a[pos].y+tms);
		--pos;
	}
	// cout<<"checking: "<<tms<<endl;
	return xl <= xr && yl <= yr;
}
int main() {
	int x, y;
	read(n), read(k);
	rep(i, 1, n) read(x), read(y), a[i] = node{x+y, y-x, inf};
	rep(i, 1, k) read(x), read(y), v[i] = mp(x+y, y-x);
	sort(v+1, v+k+1);
	rep(i, 1, k) root[i] = root[i-1], ins(root[i], -MAXM, MAXM, v[i].sec);
	rep(i, 1, n) {
		int l = 0, r = MAXM*2;
		while(l <= r) {
			if(get(a[i].x-mid, a[i].x+mid, a[i].y-mid, a[i].y+mid))
				a[i].dis = mid, r = mid-1;
			else l = mid+1;
		}
	}
	// rep(i, 1, n) cout<<a[i].dis<<' ';
	// puts("");
	sort(a+1, a+n+1);
	int l = 0, r = MAXM*2, ans;
	while(l <= r) {
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	return 0;
}


#include <bits/stdc++.h>
#define il inline
#define ri register int
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define mid ((l+r)>>1)
#define MAXN 100050
#define MAXM 100000000
#define mod
#define inf 1000000000
#define eps (1e-6)
#define alpha 0.75
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define repd(i, x, y) for(ri i = x; i >= y; --i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ll, int> pli;
typedef pair <int, ll> pil;
typedef pair <ll, ll> pll;
template <typename T> inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <typename T> inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
il void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = x*10+ch-'0', ch = getchar();
	x *= f;
}
int n, k, ch[MAXN<<2][2], size[MAXN<<5], tcnt, root[MAXN];
struct node {
	int x, y, dis;
	bool operator < (const node &a) const {
		return dis < a.dis;
	}
} a[MAXN];
pii v[MAXN];
void copy(int u, int p) {
	rep(i, 0, 1) ch[u][i] = ch[p][i];
	size[u] = size[p];
}
void ins(int &u, int l, int r, int x) {
	int tmp = u; u = ++tcnt, copy(u, tmp);
	++size[u];
	if(l == r) return ;
	if(x <= mid) ins(ch[u][0], l, mid, x);
	else ins(ch[u][1], mid+1, r, x);
}
int query(int u, int l, int r, int tl, int tr) {
	if(!u) return 0;
	if(tl <= l && r <= tr) return size[u];
	int ret = 0;
	if(tl <= mid) ret += query(ch[u][0], l, mid, tl, tr);
	if(mid < tr) ret += query(ch[u][1], mid+1, r, tl, tr);
	return ret;
}
int get(int xl, int xr, int yl, int yr) {
	int L = lower_bound(v+1, v+k+1, mp(xl, -inf))-v, R = upper_bound(v+1, v+k+1, mp(xr, inf))-v-1;
	return query(root[R], -MAXM, MAXM, yl, yr)-query(root[L-1], -MAXM, MAXM, yl, yr);
}
bool check(int tms) {
	if(tms >= a[n].dis) return 1;
	// cout<<"checking: "<<tms<<endl;
	int xl = -1e9, xr = 1e9, yl = -1e9, yr = 1e9;
	int pos = n;
	while(pos && a[pos].dis > tms) {
		chkmax(xl, a[pos].x-tms), chkmin(xr, a[pos].x+tms);
		chkmax(yl, a[pos].y-tms), chkmin(yr, a[pos].y+tms);
		--pos;
	}
	while(pos) {
		if(xl > xr || yl > yr) break;
		int t = tms-a[pos].dis;
		if(t >= 0 && get(xl-t, xr+t, yl-t, yr+t)) {
			// cout<<"success in: "<<pos<<' '<<t<<' '<<xl-t<<' '<<xr+t<<' '<<yl-t<<' '<<yr+t<<endl;
			return 1;
		}
		chkmax(xl, a[pos].x-tms), chkmin(xr, a[pos].x+tms);
		chkmax(yl, a[pos].y-tms), chkmin(yr, a[pos].y+tms);
		--pos;
	}
	// cout<<"checking: "<<tms<<endl;
	return xl <= xr && yl <= yr;
}
int main() {
	int x, y;
	read(n), read(k);
	rep(i, 1, n) read(x), read(y), a[i] = node{x+y, y-x, inf};
	rep(i, 1, k) read(x), read(y), v[i] = mp(x+y, y-x);
	sort(v+1, v+k+1);
	rep(i, 1, k) root[i] = root[i-1], ins(root[i], -MAXM, MAXM, v[i].sec);
	rep(i, 1, n) {
		int l = 0, r = MAXM*2;
		while(l <= r) {
			if(get(a[i].x-mid, a[i].x+mid, a[i].y-mid, a[i].y+mid))
				a[i].dis = mid, r = mid-1;
			else l = mid+1;
		}
	}
	// rep(i, 1, n) cout<<a[i].dis<<' ';
	// puts("");
	sort(a+1, a+n+1);
	int l = 0, r = MAXM*2, ans;
	while(l <= r) {
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	return 0;
}


#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define il inline
#define ri register int
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define mid ((l+r)>>1)
#define MAXN 200050
#define MAXM 200000000
#define mod
#define inf 1000000000
#define eps (1e-6)
#define alpha 0.75
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define repd(i, x, y) for(ri i = x; i >= y; --i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ll, int> pli;
typedef pair <int, ll> pil;
typedef pair <ll, ll> pll;
template <typename T> inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <typename T> inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
il void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = x*10+ch-'0', ch = getchar();
	x *= f;
}
int n, k, ccnt, ch[MAXN<<5][2], size[MAXN<<5], tcnt, root[MAXN], b[MAXN];
struct node {
	int x, y, dis;
	bool operator < (const node &a) const {
		return dis < a.dis;
	}
} a[MAXN];
pii v[MAXN];
il void copy(int u, int p) {
	rep(i, 0, 1) ch[u][i] = ch[p][i];
	size[u] = size[p];
}
il void ins(int &u, int l, int r, int x) {
	int tmp = u; u = ++tcnt, copy(u, tmp);
	++size[u];
	if(l == r) return ;
	if(x <= mid) ins(ch[u][0], l, mid, x);
	else ins(ch[u][1], mid+1, r, x);
}
il int query(int u, int l, int r, int tl, int tr) {
	if(!u) return 0;
	if(tl <= l && r <= tr) return size[u];
	int ret = 0;
	if(tl <= mid) ret += query(ch[u][0], l, mid, tl, tr);
	if(mid < tr) ret += query(ch[u][1], mid+1, r, tl, tr);
	return ret;
}
il int get(int xl, int xr, int yl, int yr) {
	xl = lower_bound(v+1, v+k+1, mp(xl, -inf))-v, xr = upper_bound(v+1, v+k+1, mp(xr, inf))-v-1;
	yl = lower_bound(b+1, b+ccnt+1, yl)-b, yr = upper_bound(b+1, b+ccnt+1, yr)-b-1;
	return query(root[xr], 1, ccnt, yl, yr)-query(root[xl-1], 1, ccnt, yl, yr);
}
il bool check(int tms) {
	int xl = -inf, xr = inf, yl = -inf, yr = inf;
	repd(i, n, 1) {
		if(xl > xr || yl > yr) break;
		int t = tms-a[i].dis;
		if(t >= 0 && get(xl-t, xr+t, yl-t, yr+t)) return 1;
		chkmax(xl, a[i].x-tms), chkmin(xr, a[i].x+tms);
		chkmax(yl, a[i].y-tms), chkmin(yr, a[i].y+tms);
	}
	// cout<<"checking: "<<tms<<endl;
	return xl <= xr && yl <= yr;
}
int main() {
	int x, y;
	read(n), read(k);
	rep(i, 1, n) read(x), read(y), a[i] = node{x+y, y-x, inf};
	rep(i, 1, k) read(x), read(y), v[i] = mp(x+y, y-x), b[i] = v[i].sec;
	sort(v+1, v+k+1), sort(b+1, b+k+1);
	ccnt = unique(b+1, b+k+1)-b-1;
	rep(i, 1, k) v[i].sec = lower_bound(b+1, b+ccnt+1, v[i].sec)-b;
	rep(i, 1, k) root[i] = root[i-1], ins(root[i], 1, ccnt, v[i].sec);
	rep(i, 1, n) {
		int l = 0, r = MAXM*2;
		while(l <= r) {
			if(get(a[i].x-mid, a[i].x+mid, a[i].y-mid, a[i].y+mid))
				a[i].dis = mid, r = mid-1;
			else l = mid+1;
		}
	}
	// rep(i, 1, n) cout<<a[i].dis<<' ';
	// puts("");
	sort(a+1, a+n+1);
	int l = 0, r = MAXM*2, ans;
	while(l <= r) {
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	return 0;
}


#include <bits/stdc++.h>
#define il inline
#define ri register int
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define mid ((l+r)>>1)
#define MAXN 200050
#define MAXM 100000000
#define mod
#define inf 1000000000
#define eps (1e-6)
#define alpha 0.75
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define repd(i, x, y) for(ri i = x; i >= y; --i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ll, int> pli;
typedef pair <int, ll> pil;
typedef pair <ll, ll> pll;
template <typename T> inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <typename T> inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
il void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = x*10+ch-'0', ch = getchar();
	x *= f;
}
int n, k, ch[MAXN<<5][2], size[MAXN<<5], tcnt, root[MAXN];
struct node {
	int x, y, dis;
	bool operator < (const node &a) const {
		return dis < a.dis;
	}
} a[MAXN];
pii v[MAXN];
void copy(int u, int p) {
	rep(i, 0, 1) ch[u][i] = ch[p][i];
	size[u] = size[p];
}
void ins(int &u, int l, int r, int x) {
	int tmp = u; u = ++tcnt, copy(u, tmp);
	++size[u];
	if(l == r) return ;
	if(x <= mid) ins(ch[u][0], l, mid, x);
	else ins(ch[u][1], mid+1, r, x);
}
int query(int u, int l, int r, int tl, int tr) {
	if(!u) return 0;
	if(tl <= l && r <= tr) return size[u];
	int ret = 0;
	if(tl <= mid) ret += query(ch[u][0], l, mid, tl, tr);
	if(mid < tr) ret += query(ch[u][1], mid+1, r, tl, tr);
	return ret;
}
int get(int xl, int xr, int yl, int yr) {
	int L = lower_bound(v+1, v+k+1, mp(xl, -inf))-v, R = upper_bound(v+1, v+k+1, mp(xr, inf))-v-1;
	return query(root[R], -MAXM, MAXM, yl, yr)-query(root[L-1], -MAXM, MAXM, yl, yr);
}
bool check(int tms) {
	int xl = -1e9, xr = 1e9, yl = -1e9, yr = 1e9;
	repd(i, n, 1) {
		if(xl > xr || yl > yr) break;
		int t = tms-a[i].dis;
		if(t >= 0 && get(xl-t, xr+t, yl-t, yr+t)) return 1;
		chkmax(xl, a[i].x-tms), chkmin(xr, a[i].x+tms);
		chkmax(yl, a[i].y-tms), chkmin(yr, a[i].y+tms);
	}
	// cout<<"checking: "<<tms<<endl;
	return xl <= xr && yl <= yr;
}
int main() {
	int x, y;
	read(n), read(k);
	rep(i, 1, n) read(x), read(y), a[i] = node{x+y, y-x, inf};
	rep(i, 1, k) read(x), read(y), v[i] = mp(x+y, y-x);
	sort(v+1, v+k+1);
	rep(i, 1, k) root[i] = root[i-1], ins(root[i], -MAXM, MAXM, v[i].sec);
	rep(i, 1, n) {
		int l = 0, r = MAXM*2;
		while(l <= r) {
			if(get(a[i].x-mid, a[i].x+mid, a[i].y-mid, a[i].y+mid))
				a[i].dis = mid, r = mid-1;
			else l = mid+1;
		}
	}
	// rep(i, 1, n) cout<<a[i].dis<<' ';
	// puts("");
	sort(a+1, a+n+1);
	int l = 0, r = MAXM*2, ans;
	while(l <= r) {
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	return 0;
}


#include <bits/stdc++.h>
#define il inline
#define ri register int
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define mid ((l+r)>>1)
#define MAXN 200050
#define MAXM 200000000
#define mod
#define inf 1000000000
#define eps (1e-6)
#define alpha 0.75
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define repd(i, x, y) for(ri i = x; i >= y; --i)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair <int, int> pii;
typedef pair <ll, int> pli;
typedef pair <int, ll> pil;
typedef pair <ll, ll> pll;
template <typename T> inline bool chkmin(T &x, T y) {return x > y ? x = y, 1 : 0;}
template <typename T> inline bool chkmax(T &x, T y) {return x < y ? x = y, 1 : 0;}
il void read(int &x) {
	char ch = getchar(); int f = 1; x = 0;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') x = x*10+ch-'0', ch = getchar();
	x *= f;
}
int n, k, ch[MAXN<<5][2], size[MAXN<<5], tcnt, root[MAXN];
struct node {
	int x, y, dis;
	bool operator < (const node &a) const {
		return dis < a.dis;
	}
} a[MAXN];
pii v[MAXN];
void copy(int u, int p) {
	rep(i, 0, 1) ch[u][i] = ch[p][i];
	size[u] = size[p];
}
void ins(int &u, int l, int r, int x) {
	int tmp = u; u = ++tcnt, copy(u, tmp);
	++size[u];
	if(l == r) return ;
	if(x <= mid) ins(ch[u][0], l, mid, x);
	else ins(ch[u][1], mid+1, r, x);
}
int query(int u, int l, int r, int tl, int tr) {
	if(!u) return 0;
	if(tl <= l && r <= tr) return size[u];
	int ret = 0;
	if(tl <= mid) ret += query(ch[u][0], l, mid, tl, tr);
	if(mid < tr) ret += query(ch[u][1], mid+1, r, tl, tr);
	return ret;
}
int get(int xl, int xr, int yl, int yr) {
	int L = lower_bound(v+1, v+k+1, mp(xl, -inf))-v, R = upper_bound(v+1, v+k+1, mp(xr, inf))-v-1;
	return query(root[R], -MAXM, MAXM, yl, yr)-query(root[L-1], -MAXM, MAXM, yl, yr);
}
bool check(int tms) {
	int xl = -1e9, xr = 1e9, yl = -1e9, yr = 1e9;
	repd(i, n, 1) {
		if(xl > xr || yl > yr) break;
		int t = tms-a[i].dis;
		if(t >= 0 && get(xl-t, xr+t, yl-t, yr+t)) return 1;
		chkmax(xl, a[i].x-tms), chkmin(xr, a[i].x+tms);
		chkmax(yl, a[i].y-tms), chkmin(yr, a[i].y+tms);
	}
	// cout<<"checking: "<<tms<<endl;
	return xl <= xr && yl <= yr;
}
int main() {
	int x, y;
	read(n), read(k);
	rep(i, 1, n) read(x), read(y), a[i] = node{x+y, y-x, inf};
	rep(i, 1, k) read(x), read(y), v[i] = mp(x+y, y-x);
	sort(v+1, v+k+1);
	rep(i, 1, k) root[i] = root[i-1], ins(root[i], -MAXM, MAXM, v[i].sec);
	rep(i, 1, n) {
		int l = 0, r = MAXM*2;
		while(l <= r) {
			if(get(a[i].x-mid, a[i].x+mid, a[i].y-mid, a[i].y+mid))
				a[i].dis = mid, r = mid-1;
			else l = mid+1;
		}
	}
	// rep(i, 1, n) cout<<a[i].dis<<' ';
	// puts("");
	sort(a+1, a+n+1);
	int l = 0, r = MAXM*2, ans;
	while(l <= r) {
		if(check(mid)) ans = mid, r = mid-1;
		else l = mid+1;
	}
	printf("%d\n", ans);
	return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <limits.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <string>
#include <functional>
#include <vector>
#include <numeric>
#include <deque>
#include <bitset>
#include <iostream>
using namespace std;
typedef long long lint;
typedef long double llf;
typedef pair<int, int> pi;
const int mod = 1e9 + 7;

struct t1{
	int first, second, nsub;
};

int n, m;
t1 a[100005];
pi b[100005];

vector<int> vx;

struct seg{
	set<int> tree[270000];
	int lim;
	void init(int n, pi *b){
		for(int i=0; i<n; i++){
			vx.push_back(b[i].first);
		}
		for(lim = 1; lim <= n; lim <<= 1);
		sort(vx.begin(), vx.end());
		vx.resize(unique(vx.begin(), vx.end()) - vx.begin());
		for(int i=0; i<n; i++){
			int t1 = lower_bound(vx.begin(), vx.end(), b[i].first) - vx.begin();
			t1 += lim;
			while(t1){
				tree[t1].insert(b[i].second);
				t1 >>= 1;
			}
		}
	}
	int query(int s, int e, int sy, int ey){
		s += lim;
		e += lim;
		while(s < e){
			if(s%2 == 1){
				auto t = tree[s].lower_bound(sy);
				if(t != tree[s].end() && *t <= ey) return 1;
				s++;
			}
			if(e%2 == 0){
				auto t = tree[e].lower_bound(sy);
				if(t != tree[e].end() && *t <= ey) return 1;
				e--;
			}
			s >>= 1;
			e >>= 1;
		}
		if(s == e){
			auto t = tree[s].lower_bound(sy);
			if(t != tree[s].end() && *t <= ey) return 1;
		}
		return 0;
	}
}seg;

bool query(int sx, int ex, int sy, int ey){
	int t1 = lower_bound(vx.begin(), vx.end(), sx) - vx.begin();
	int t2 = upper_bound(vx.begin(), vx.end(), ex) - vx.begin() - 1;
	return seg.query(t1, t2, sy, ey);
}

bool ok(int sx, int ex, int sy, int ey, int d2){
	if(sx > ex || sy > ey || d2 < 0) return 0;
	return query(sx - d2, ex + d2, sy - d2, ey + d2);
}

int main(){
	cin >> n >> m;
	for(int i=0; i<n; i++){
		int x, y;
		scanf("%d %d",&x,&y);
		a[i] = {x+y, x-y, -1};
	}
	int ret = 1e9;
	int maxx = -1e9, minx = 1e9, maxy = -1e9, miny = 1e9;
	for(int i=0; i<n; i++){
		maxx = max(maxx, a[i].first);
		minx = min(minx, a[i].first);
		maxy = max(maxy, a[i].second);
		miny = min(miny, a[i].second);
	}
	ret = min(ret, max(maxx-minx+1, maxy-miny+1) / 2);
	if(m == 0){
		printf("%d",ret);
		return 0;
	}
	for(int i=0; i<m; i++){
		int x, y;
		scanf("%d %d",&x,&y);
		b[i] = pi(x+y, x-y);
	}
	seg.init(m, b);
	for(int i=0; i<n; i++){
		a[i].nsub = 1e9;
		int s = 0, e = 5e8;
		while(s != e){
			int m = (s+e)/2;
			if(query(a[i].first - m, a[i].first + m, a[i].second - m, a[i].second + m)){
				e = m;
			}
			else s = m+1;
		}
		a[i].nsub = s;
	}
	sort(a, a+n, [&](const t1 &a, const t1 &b){
		return a.nsub > b.nsub;
	});
	vector<int> cnd;
	for(int i=0; i<n; i++){
		cnd.push_back(a[i].nsub);
	}
	sort(cnd.begin(), cnd.end());
	cnd.resize(unique(cnd.begin(), cnd.end()) - cnd.begin());
	ret = min(ret, cnd.back());
	reverse(cnd.begin(), cnd.end());
	int pnt = 0;
	int sx = -1e9, ex = 1e9, sy = -1e9, ey = 1e9;
	for(auto &i : cnd){
		while(pnt < n && a[pnt].nsub > i){
			sx = max(sx, a[pnt].first);
			ex = min(ex, a[pnt].first);
			sy = max(sy, a[pnt].second);
			ey = min(ey, a[pnt].second);
			pnt++;
		}
		int s = 0, e = 5e8;
		while(s != e){
			int m = (s+e)/2;
			if(ok(sx-m, ex+m, sy-m, ey+m, m-i)) e = m;
			else s = m+1;
		}
		ret = min(ret, s);
	}
	cout << ret;
}


#include<bits/stdc++.h>
using namespace std;

#define int long long
int read(){
	int a = 0; bool f = 0; char c = getchar(); while(!isdigit(c)){f = c == '-'; c = getchar();}
	while(isdigit(c)){a = a * 10 + c - 48; c = getchar();} return f ? -a : a;
}

#define pii pair < int , int >
const int _ = 2e5 + 7; pii sub[_]; int N , M , ans = 1e9;
struct peo{int x , y , t;}p[_];
bool cmpt(peo p , peo q){return p.t > q.t;}
bool cmpx(peo p , peo q){return p.x < q.x || p.x == q.x && p.y < q.y || p.x == q.x && p.y == q.y && p.t < q.t;}

#define mid ((l + r) >> 1)
const int __ = _ << 5 , INF = 2e8;
int ch[__][2] , sz[__] , cnode;
void ins(int &x , int l , int r , int t){
	int tmp = ++cnode; ch[tmp][0] = ch[x][0]; ch[tmp][1] = ch[x][1]; sz[tmp] = sz[x] + 1; x = tmp;
	if(l != r) mid >= t ? ins(ch[x][0] , l , mid , t) : ins(ch[x][1] , mid + 1 , r , t);
}

int qry(int x , int l , int r , int L , int R){
	if(!sz[x] || (l >= L && r <= R)) return sz[x];
	int sum = 0; if(mid >= L) sum = qry(ch[x][0] , l , mid , L , R);
	if(mid < R) sum += qry(ch[x][1] , mid + 1 , r , L , R);
	return sum;
}
#undef mid
int rt[_];

int qry_rect(int x1 , int x2 , int y1 , int y2){
	if(y2 < -INF || y1 > INF) return 0;
	int pl = lower_bound(sub + 1 , sub + M + 1 , pii(x1 , -INF)) - sub - 1 ,
		pr = lower_bound(sub + 1 , sub + M + 1 , pii(x2 + 1 , -INF)) - sub - 1;
	return qry(rt[pr] , -INF , INF , y1 , y2) - qry(rt[pl] , -INF , INF , y1 , y2);
}

#define lowbit(x) (x & -x)
struct bit{
	int sz , arr[_]; bit(){memset(arr , -0x3f , sizeof(arr));}
	void add(int x , int v){while(x <= sz){arr[x] = max(arr[x] , v); x += lowbit(x);}}
	int qry(int x){int ans = arr[0]; while(x){ans = max(ans , arr[x]); x -= lowbit(x);} return ans;}
};

signed main(){
	N = read(); M = read(); for(int i = 1 ; i <= N ; ++i){p[i].x = read(); p[i].y = read(); p[i].t = 1e9;}
	for(int i = 1 ; i <= M ; ++i){sub[i].first = read(); sub[i].second = read();}

	vector < peo > pot; for(int i = 1 ; i <= N ; ++i) pot.push_back(p[i]);
	for(int i = 1 ; i <= M ; ++i) pot.push_back((peo){sub[i].first , sub[i].second , -1});
	for(int i = 0 ; i < 4 ; ++i){
		sort(pot.begin() , pot.end() , cmpx); vector < int > valy; valy.push_back(-INF - 1);
		for(auto t : pot) valy.push_back(t.y);
		sort(valy.begin() , valy.end()); bit calc; calc.sz = valy.size();

		for(auto &t : pot)
			if(t.t == -1) calc.add(lower_bound(valy.begin() , valy.end() , t.y) - valy.begin() , t.x + t.y);
			else t.t = min(t.t , t.x + t.y - calc.qry(lower_bound(valy.begin() , valy.end() , t.y) - valy.begin()));

		for(auto &t : pot) i & 1 ? t.x = -t.x : t.y = -t.y;
	}
	N = 0; for(auto t : pot) if(t.t != -1) p[++N] = t;
	for(int i = 1 ; i <= N ; ++i){p[i].x += p[i].y; p[i].y = p[i].x - 2 * p[i].y;}
	for(int i = 1 ; i <= M ; ++i){sub[i].first += sub[i].second; sub[i].second = sub[i].first - 2 * sub[i].second;}
	sort(sub + 1 , sub + M + 1); for(int i = 1 ; i <= M ; ++i) ins(rt[i] = rt[i - 1] , -INF , INF , sub[i].second);

	sort(p + 1 , p + N + 1 , cmpt); ans = p[1].t; int mnx = INF , mxx = -INF , mny = INF , mxy = -INF; p[N + 1].t = -INF;
	for(int i = 1 ; i <= N ; ++i){
		mnx = min(mnx , p[i].x); mxx = max(mxx , p[i].x); mny = min(mny , p[i].y); mxy = max(mxy , p[i].y);
		int l = max(p[i + 1].t , max((mxx - mnx + 1) / 2 , (mxy - mny + 1) / 2)) , r = INF;
		if(!M){
			if(i == N) ans = l;
			continue;
		}
		while(l < r){
			int mid = (l + r) >> 1 , more = mid - p[i + 1].t;
			qry_rect(mxx - mid - more , mnx + mid + more , mxy - mid - more , mny + mid + more) ? r = mid : l = mid + 1;
		}
		int more = l - p[i + 1].t , sum = qry_rect(mxx - l - more , mnx + l + more , mxy - l - more , mny + l + more);
		mxx -= l; mnx += l; mxy -= l; mny += l;
		if(mxx == mnx && mxy == mny && (mxx + mxy) % 2){++l; --mxx; ++mnx; --mxy; ++mny;}
		else if(i != N){
			if(mxx == mnx){
				if((mxx + mxy) & 1) sum -= qry_rect(mxx - more , mnx + more , mxy - more , mxy - more);
				if((mxx + mny) & 1) sum -= qry_rect(mxx - more , mnx + more , mny + more , mny + more);
			}
			if(mxy == mny){
				if((mny + mxx) & 1) sum -= qry_rect(mxx - more , mxx - more , mxy - more , mny + more);
				if((mny + mnx) & 1) sum -= qry_rect(mnx + more , mnx + more , mxy - more , mny + more);
			}
			if(!sum){++l; --mxx; ++mnx; --mxy; ++mny;}
		}
		ans = min(ans , l); mxx += l; mnx -= l; mxy += l; mny -= l;
	}
	cout << ans; return 0;
}


//starusc
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4,inf=0x3f3f3f3f;
namespace sz{
	int n,t[N<<1];
	inline void clear(int cn){
		n=cn;
		for(int i=1;i<=n;i++)t[i]=-inf;
	}
	inline void add(int x,int v){
		for(;x<=n;x+=x&-x)t[x]=max(t[x],v);
	}
	inline int ask(int x){
		int ret=-inf;
		for(;x;x-=x&-x)ret=max(ret,t[x]);
		return ret;
	}
}
int lim,tot;
namespace seg{
	const int M=2e6+4;
	#define lc ch[p][0]
	#define rc ch[p][1]
	int ch[M][2],t[M];
	void insert(int &p,int l,int r,int x){
		if(p<=lim){
			ch[++tot][0]=ch[p][0];ch[tot][1]=ch[p][1];
			t[tot]=t[p];p=tot;
		}
		t[p]++;
		if(l==r)return;
		int mid=l+r>>1;
		if(x<=mid)insert(lc,l,mid,x);
		else insert(rc,mid+1,r,x);
	}
	int query(int p,int l,int r,int ql,int qr){
		if(!p||(ql<=l&&r<=qr))return t[p];
		int mid=l+r>>1;
		if(qr<=mid)return query(lc,l,mid,ql,qr);
		if(mid<ql)return query(rc,mid+1,r,ql,qr);
		return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
	}
}
struct poin{
	int x,y,id;
}a[N],b[N],c[N<<1];
int d[N<<1],lx[N],ly[N],rt[N];
inline bool comp_x(const poin &a,const poin &b){
	return a.x==b.x?(a.y==b.y?a.id<b.id:a.y<b.y):a.x<b.x;
}
inline bool comp_v(const poin &a,const poin &b){
	return a.id<b.id;
}
inline bool ask(int l1,int r1,int l2,int r2){
	l1=lower_bound(lx+1,lx+lx[0]+1,l1)-lx;
	r1=upper_bound(lx+1,lx+lx[0]+1,r1)-lx-1;
	l2=lower_bound(ly+1,ly+ly[0]+1,l2)-ly;
	r2=upper_bound(ly+1,ly+ly[0]+1,r2)-ly-1;
	return seg::query(rt[r1],1,ly[0],l2,r2)!=seg::query(rt[l1-1],1,ly[0],l2,r2);
}
inline void findnear(int n){
	sort(c+1,c+n+1,comp_x);
	for(int i=1;i<=n;i++)d[i]=c[i].y;
	sort(d+1,d+n+1);
	int cn=unique(d+1,d+n+1)-d-1;
	sz::clear(cn);
	for(int i=1,r;i<=n;i++){
		r=lower_bound(d+1,d+cn+1,c[i].y)-d;
		if(c[i].id){
			a[c[i].id].id=min(a[c[i].id].id,c[i].x+c[i].y-sz::ask(r));
		}
		else{
			sz::add(r,c[i].x+c[i].y);
		}
	}
}
int n,m;
vector<int>vec[N];
int main(){
//	freopen("subway.in","r",stdin);
//	freopen("subway.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++){
		a[i].x=c[i].x=read();a[i].y=c[i].y=read();
		a[i].id=inf;
		c[i].id=i;
	}
	for(int i=1;i<=m;i++){
		b[i].x=c[i+n].x=read();b[i].y=c[i+n].y=read();
	}
	findnear(n+m);
	for(int i=1;i<=n+m;i++)c[i].x=-c[i].x;
	findnear(n+m);
	for(int i=1;i<=n+m;i++)c[i].y=-c[i].y;
	findnear(n+m);
	for(int i=1;i<=n+m;i++)c[i].x=-c[i].x;
	findnear(n+m);
	// for(int i=1;i<=n;i++)cout<<a[i].id<<" ";
	// puts("");
	for(int i=1,u,v;i<=n;i++){
		u=a[i].x;v=a[i].y;
		a[i].x=u+v;a[i].y=u-v;
	}
	for(int i=1,u,v;i<=m;i++){
		u=b[i].x;v=b[i].y;
		b[i].x=u+v;b[i].y=u-v;
	}
	for(int i=1;i<=m;i++){
		lx[++lx[0]]=b[i].x;
		ly[++ly[0]]=b[i].y;
	}
	lx[++lx[0]]=ly[++ly[0]]=inf;
	lx[++lx[0]]=ly[++ly[0]]=-inf;
	sort(lx+1,lx+lx[0]+1);
	sort(ly+1,ly+ly[0]+1);
	lx[0]=unique(lx+1,lx+lx[0]+1)-lx-1;
	ly[0]=unique(ly+1,ly+ly[0]+1)-ly-1;
	for(int i=1,x;i<=m;i++){
		x=lower_bound(lx+1,lx+lx[0],b[i].x)-lx;
		vec[x].push_back(i);
	}
	for(int i=1,y;i<=lx[0];i++){
		rt[i]=rt[i-1];
		for(auto v:vec[i]){
			y=lower_bound(ly+1,ly+ly[0]+1,b[v].y)-ly;
			seg::insert(rt[i],1,ly[0],y);
		}
		lim=tot;
	}
	sort(a+1,a+n+1,comp_v);
	int l=0,r=inf/2,mid,l1,r1,l2,r2,fl;
	while(l<r){
		mid=l+r>>1;
		l1=l2=-inf/4;
		r1=r2=inf/4;
		fl=0;
		for(int i=n,d;i&&l1<=r1&&l2<=r2;i--){
			d=mid-a[i].id;
			if(d>=0){
				fl|=ask(l1-d,r1+d,l2-d,r2+d);
			}
			l1=max(l1,a[i].x-mid);
			r1=min(r1,a[i].x+mid);
			l2=max(l2,a[i].y-mid);
			r2=min(r2,a[i].y+mid);
		}
		fl|=(l1<=r1&&l2<=r2);
		if(fl)r=mid;
		else l=mid+1;
	}
	cout<<r;
	return (0-0);
}
/*
3 4
-4 1
0 -3
-2 3
-1 -2
2 1
0 -3
-1 3
*/


//starusc
#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=2e5+4,inf=0x3f3f3f3f;
namespace sz{
	int n,t[N<<1];
	inline void clear(int cn){
		n=cn;
		for(int i=1;i<=n;i++)t[i]=-inf;
	}
	inline void add(int x,int v){
		for(;x<=n;x+=x&-x)t[x]=max(t[x],v);
	}
	inline int ask(int x){
		int ret=-inf;
		for(;x;x-=x&-x)ret=max(ret,t[x]);
		return ret;
	}
}
int lim,tot;
namespace seg{
	const int M=4e6+4;
	#define lc ch[p][0]
	#define rc ch[p][1]
	int ch[M][2],t[M];
	void insert(int &p,int l,int r,int x){
		if(p<=lim){
			ch[++tot][0]=ch[p][0];ch[tot][1]=ch[p][1];
			t[tot]=t[p];p=tot;
		}
		t[p]++;
		if(l==r)return;
		int mid=l+r>>1;
		if(x<=mid)insert(lc,l,mid,x);
		else insert(rc,mid+1,r,x);
	}
	int query(int p,int l,int r,int ql,int qr){
		if(!p||(ql<=l&&r<=qr))return t[p];
		int mid=l+r>>1;
		if(qr<=mid)return query(lc,l,mid,ql,qr);
		if(mid<ql)return query(rc,mid+1,r,ql,qr);
		return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
	}
}
struct poin{
	int x,y,id;
}a[N],b[N],c[N<<1];
int d[N<<1],lx[N],ly[N],rt[N];
inline bool comp_x(const poin &a,const poin &b){
	return a.x==b.x?(a.y==b.y?a.id<b.id:a.y<b.y):a.x<b.x;
}
inline bool comp_v(const poin &a,const poin &b){
	return a.id<b.id;
}
inline bool ask(int l1,int r1,int l2,int r2){
	l1=lower_bound(lx+1,lx+lx[0]+1,l1)-lx;
	r1=upper_bound(lx+1,lx+lx[0]+1,r1)-lx-1;
	l2=lower_bound(ly+1,ly+ly[0]+1,l2)-ly;
	r2=upper_bound(ly+1,ly+ly[0]+1,r2)-ly-1;
	return seg::query(rt[r1],1,ly[0],l2,r2)!=seg::query(rt[l1-1],1,ly[0],l2,r2);
}
inline void findnear(int n){
	sort(c+1,c+n+1,comp_x);
	for(int i=1;i<=n;i++)d[i]=c[i].y;
	sort(d+1,d+n+1);
	int cn=unique(d+1,d+n+1)-d-1;
	sz::clear(cn);
	for(int i=1,r;i<=n;i++){
		r=lower_bound(d+1,d+cn+1,c[i].y)-d;
		if(c[i].id){
			a[c[i].id].id=min(a[c[i].id].id,c[i].x+c[i].y-sz::ask(r));
		}
		else{
			sz::add(r,c[i].x+c[i].y);
		}
	}
}
int n,m;
vector<int>vec[N];
int main(){
//	freopen("subway.in","r",stdin);
//	freopen("subway.out","w",stdout);
	n=read();m=read();
	for(int i=1;i<=n;i++){
		a[i].x=c[i].x=read();a[i].y=c[i].y=read();
		a[i].id=inf;
		c[i].id=i;
	}
	for(int i=1;i<=m;i++){
		b[i].x=c[i+n].x=read();b[i].y=c[i+n].y=read();
	}
	findnear(n+m);
	for(int i=1;i<=n+m;i++)c[i].x=-c[i].x;
	findnear(n+m);
	for(int i=1;i<=n+m;i++)c[i].y=-c[i].y;
	findnear(n+m);
	for(int i=1;i<=n+m;i++)c[i].x=-c[i].x;
	findnear(n+m);
	for(int i=1,u,v;i<=n;i++){
		u=a[i].x;v=a[i].y;
		a[i].x=u+v;a[i].y=u-v;
	}
	for(int i=1,u,v;i<=m;i++){
		u=b[i].x;v=b[i].y;
		b[i].x=u+v;b[i].y=u-v;
	}
	for(int i=1;i<=m;i++){
		lx[++lx[0]]=b[i].x;
		ly[++ly[0]]=b[i].y;
	}
	lx[++lx[0]]=ly[++ly[0]]=inf;
	lx[++lx[0]]=ly[++ly[0]]=-inf;
	sort(lx+1,lx+lx[0]+1);
	sort(ly+1,ly+ly[0]+1);
	lx[0]=unique(lx+1,lx+lx[0]+1)-lx-1;
	ly[0]=unique(ly+1,ly+ly[0]+1)-ly-1;
	for(int i=1,x;i<=m;i++){
		x=lower_bound(lx+1,lx+lx[0],b[i].x)-lx;
		vec[x].push_back(i);
	}
	for(int i=1,y;i<=lx[0];i++){
		rt[i]=rt[i-1];
		for(auto v:vec[i]){
			y=lower_bound(ly+1,ly+ly[0]+1,b[v].y)-ly;
			seg::insert(rt[i],1,ly[0],y);
		}
		lim=tot;
	}
	sort(a+1,a+n+1,comp_v);
	int l=0,r=inf/2,mid,l1,r1,l2,r2,fl;
	while(l<r){
		mid=l+r>>1;
		l1=l2=-inf/4;
		r1=r2=inf/4;
		fl=0;
		for(int i=n,d;i&&l1<=r1&&l2<=r2;i--){
			d=mid-a[i].id;
			if(d>=0){
				fl=ask(l1-d,r1+d,l2-d,r2+d);
				if(fl)break;
			}
			l1=max(l1,a[i].x-mid);
			r1=min(r1,a[i].x+mid);
			l2=max(l2,a[i].y-mid);
			r2=min(r2,a[i].y+mid);
		}
		fl|=(l1<=r1&&l2<=r2);
		if(fl)r=mid;
		else l=mid+1;
	}
	cout<<r;
	return (0-0);
}


#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef vector<int> vi;
typedef long long ll;
typedef pair<int,int> pii;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
const int inf=1e9;

int n,m,px[N],py[N],sx[N],sy[N],dis[N],r[N];
bool ans[N];

bool valid(int x,int y) {
	return abs(x+y)&1^1;
}

struct rect {
	int x1,y1,x2,y2;
	void unite(const rect &A) {
		x1=max(x1,A.x1);
		x2=min(x2,A.x2);
		y1=max(y1,A.y1);
		y2=min(y2,A.y2);
	}
	bool empty() {
		return x1>x2||y1>y2;
	}
	rect extend(int r) const {
		return (rect){x1-r,y1-r,x2+r,y2+r};
	}
	void red() {
		if(x1==x2) {
			if(!valid(x1,y1)) ++y1;
			if(!valid(x1,y2)) --y2;
		}
		else if(y1==y2) {
			if(!valid(x1,y1)) ++x1;
			if(!valid(x2,y1)) --x2;
		}
	}
} q[N];

void rotate(int &x,int &y) {
	int new_x=x+y,new_y=x-y;
	x=new_x;y=new_y;
}

struct lsh {
	int st[N],tp;
	void insert(int x) {
		st[++tp]=x;
	}
	void build() {
		sort(st+1,st+tp+1);
		tp=unique(st+1,st+tp+1)-st-1;
	}
	int find_ge(int x) {
		return lower_bound(st+1,st+tp+1,x)-st;
	}
	int find_le(int x) {
		return upper_bound(st+1,st+tp+1,x)-st-1;
	}
	void clear() {
		tp=0;
	}
} lsh_x,lsh_y;

int tr[N];

void modify(int p) {
	while(p<N) ++tr[p],p+=p&-p;
}

int query(int p) {
	int ret=0;
	while(p) ret+=tr[p],p-=p&-p;
	return ret;
}

bool check(rect *q,int tt) {
	static vi mdf[N],qry[N];
	static int mem[N];
	for(int i=0;i<N;i++) mdf[i].clear(),qry[i].clear(),mem[i]=0;
	memset(tr,0,sizeof(tr));
	for(int i=1;i<=tt;i++) {
		int x1=lsh_x.find_ge(q[i].x1),y1=lsh_y.find_ge(q[i].y1);
		int x2=lsh_x.find_le(q[i].x2),y2=lsh_y.find_le(q[i].y2);
		q[i]=(rect){x1,y1,x2,y2};
		if(x1<=x2&&y1<=y2) qry[x1-1].pb(-i),qry[x2].pb(i);
		else ans[i]=0;
	}
	for(int i=1;i<=m;i++) mdf[sx[i]].pb(i);
	for(int i=1;i<=lsh_x.tp;i++) {
		for(auto t:mdf[i]) modify(sy[t]);
		for(auto t:qry[i]) {
			if(t<0) t=-t,mem[t]=query(q[t].y2)-query(q[t].y1-1);
			else if(mem[t]!=query(q[t].y2)-query(q[t].y1-1)) return 1;
		}
	}
	return 0;
}

bool check(int mid) {
	rect u=(rect){-inf,-inf,inf,inf};
	vi all;
	for(int i=1;i<=n;i++) {
		if(dis[i]<=mid) r[i]=mid-dis[i],all.pb(i);
		else {
			u.unite((rect){px[i]-mid,py[i]-mid,px[i]+mid,py[i]+mid});
			u.red();
		}
		if(u.empty()) return 0;
	}
	sort(all.begin(),all.end(),[&](int a,int b) { return r[a]<r[b]; });
	int tt=0;
	for(int i=0;i<=sz(all);i++) {
		if(i) {
			int x=all[i-1];
			u.unite((rect){px[x]-mid,py[x]-mid,px[x]+mid,py[x]+mid});
			u.red();
		}
		if(u.empty()) break;
		if(i==sz(all)) return 1;
		q[++tt]=u.extend(r[all[i]]);
	}
	return check(q,tt);
}

namespace find_nearest {
	void rotate_all() {
		for(int i=1;i<=n;i++) swap(px[i],py[i]),py[i]=-py[i];
		for(int i=1;i<=m;i++) swap(sx[i],sy[i]),sy[i]=-sy[i];
	}

	int tr[N<<2];

	void modify(int p,int v) {
		while(p<N) tr[p]=max(tr[p],v),p+=p&-p;
	}

	int query(int p) {
		int ret=-inf;
		while(p) ret=max(ret,tr[p]),p-=p&-p;
		return ret;
	}

	void _work() {
		static vi mdf[N],qry[N];
		lsh_x.clear();lsh_y.clear();
		for(int i=0;i<N;i++) mdf[i].clear(),qry[i].clear();
		for(int i=1;i<=m;i++) {
			lsh_x.insert(sx[i]);
			lsh_y.insert(sy[i]);
		}
		lsh_x.build();lsh_y.build();
		memset(tr,0xc0,sizeof(tr));
		for(int i=1;i<=m;i++) mdf[lsh_x.find_le(sx[i])].pb(i);
		for(int i=1;i<=n;i++) qry[lsh_x.find_le(px[i])].pb(i);
		for(int i=1;i<=lsh_x.tp;i++) {
			for(auto t:mdf[i]) modify(lsh_y.find_le(sy[t]),sx[t]+sy[t]);
			for(auto t:qry[i]) dis[t]=min(dis[t],px[t]+py[t]-query(lsh_y.find_le(py[t])));
		}
	}

	void work() {
		memset(dis,0x3f,sizeof(dis));
		_work();rotate_all();
		_work();rotate_all();
		_work();rotate_all();
		_work();rotate_all();
	}
}

int main() {
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>px[i]>>py[i];
	for(int i=1;i<=m;i++) cin>>sx[i]>>sy[i];
	find_nearest::work();
	lsh_x.clear();lsh_y.clear();
	for(int i=1;i<=n;i++) {
		rotate(px[i],py[i]);
	}
	for(int i=1;i<=m;i++) {
		rotate(sx[i],sy[i]);
		lsh_x.insert(sx[i]);
		lsh_y.insert(sy[i]);
	}
	lsh_x.build();lsh_y.build();
	for(int i=1;i<=m;i++) {
		sx[i]=lsh_x.find_ge(sx[i]);
		sy[i]=lsh_y.find_ge(sy[i]);
	}
	int l=0,r=2e8;
	while(l<r) {
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef vector<int> vi;
typedef long long ll;
typedef pair<int,int> pii;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sz(a) int(a.size())
const int inf=1e9;

int n,m,px[N],py[N],sx[N],sy[N],dis[N],r[N];

bool valid(int x,int y) {
	return abs(x+y)&1^1;
}

struct rect {
	int x1,y1,x2,y2;
	void unite(const rect &A) {
		x1=max(x1,A.x1);
		x2=min(x2,A.x2);
		y1=max(y1,A.y1);
		y2=min(y2,A.y2);
	}
	bool empty() {
		return x1>x2||y1>y2;
	}
	rect extend(int r) const {
		return (rect){x1-r,y1-r,x2+r,y2+r};
	}
	void red() {
		if(x1==x2) {
			if(!valid(x1,y1)) ++y1;
			if(!valid(x1,y2)) --y2;
		}
		else if(y1==y2) {
			if(!valid(x1,y1)) ++x1;
			if(!valid(x2,y1)) --x2;
		}
	}
	void print() const {
		cerr<<x1<<' '<<y1<<' '<<x2<<' '<<y2<<'\n';
	}
} q[N];

void rotate(int &x,int &y) {
	int new_x=x+y,new_y=x-y;
	x=new_x;y=new_y;
}

struct lsh {
	int st[N],tp;
	void insert(int x) {
		st[++tp]=x;
	}
	void build() {
		sort(st+1,st+tp+1);
		tp=unique(st+1,st+tp+1)-st-1;
	}
	int find_ge(int x) {
		return lower_bound(st+1,st+tp+1,x)-st;
	}
	int find_le(int x) {
		return upper_bound(st+1,st+tp+1,x)-st-1;
	}
} lsh_x,lsh_y;

int tr[N];

void modify(int p) {
	while(p<N) ++tr[p],p+=p&-p;
}

int query(int p) {
	int ret=0;
	while(p) ret+=tr[p],p-=p&-p;
	return ret;
}

bool check(rect *q,int tt) {
	static vi mdf[N],qry[N];
	static int mem[N];
	for(int i=0;i<N;i++) mdf[i].clear(),qry[i].clear(),mem[i]=0;
	memset(tr,0,sizeof(tr));
	for(int i=1;i<=tt;i++) {
		int x1=lsh_x.find_ge(q[i].x1),y1=lsh_y.find_ge(q[i].y1);
		int x2=lsh_x.find_le(q[i].x2),y2=lsh_y.find_le(q[i].y2);
		//cerr<<x1<<' '<<y1<<' '<<x2<<' '<<y2<<'\n';
		q[i]=(rect){x1,y1,x2,y2};
		if(x1<=x2&&y1<=y2) qry[x1-1].pb(-i),qry[x2].pb(i);
	}
	for(int i=1;i<=m;i++) mdf[sx[i]].pb(i);
	for(int i=1;i<=lsh_x.tp;i++) {
		for(auto t:mdf[i]) modify(sy[t]);
		for(auto t:qry[i]) {
			if(t<0) t=-t,mem[t]=query(q[t].y2)-query(q[t].y1-1);
			else {
				//cerr<<t<<' '<<query(q[t].y2)-query(q[t].y1-1)<<'\n';
				if(mem[t]!=query(q[t].y2)-query(q[t].y1-1)) {
					//cerr<<t<<'\n';
					return 1;
				}
			}
		}
	}
	return 0;
}

bool check(int mid) {
	rect u=(rect){-inf,-inf,inf,inf};
	vi all;
	for(int i=1;i<=n;i++) {
		if(dis[i]<=mid) r[i]=mid-dis[i],all.pb(i);
		else {
			u.unite((rect){px[i]-mid,py[i]-mid,px[i]+mid,py[i]+mid});
			u.red();
		}
		if(u.empty()) return 0;
	}
	sort(all.begin(),all.end(),[&](int a,int b) { return r[a]<r[b]; });
	int tt=0;
	for(int i=0;i<=sz(all);i++) {
		if(i) {
			int x=all[i-1];
			u.unite((rect){px[x]-mid,py[x]-mid,px[x]+mid,py[x]+mid});
			u.red();
		}
		if(u.empty()) break;
		if(i==sz(all)) return 1;
		q[++tt]=u.extend(r[all[i]]);
	}
	return check(q,tt);
}

namespace find_nearest {
	const int M=25000000;
	int ls[M],rs[M],tt,rt[N<<2];

	void inserty(int p,int &x,int l=1,int r=lsh_y.tp) {
		if(!x) x=++tt;
		if(l==r) return;
		int mid=(l+r)>>1;
		p<=mid?inserty(p,ls[x],l,mid):inserty(p,rs[x],mid+1,r);
	}

	bool queryy(int L,int R,int x=1,int l=1,int r=lsh_y.tp) {
		if(!x) return 0;
		if(L<=l&&r<=R) return 1;
		int mid=(l+r)>>1;
		if(L<=mid&&queryy(L,R,ls[x],l,mid)) return 1;
		if(R>mid&&queryy(L,R,rs[x],mid+1,r)) return 1;
		return 0;
	}

	void insertx(int p,int q,int x=1,int l=1,int r=lsh_x.tp) {
		inserty(q,rt[x]);
		if(l==r) return;
		int mid=(l+r)>>1;
		p<=mid?insertx(p,q,x<<1,l,mid):insertx(p,q,x<<1|1,mid+1,r);
	}

	bool queryx(int L,int R,int p,int q,int x=1,int l=1,int r=lsh_x.tp) {
		if(L>R||p>q) return 0;
		if(L<=l&&r<=R) return queryy(p,q,rt[x]);
		int mid=(l+r)>>1;
		if(L<=mid&&queryx(L,R,p,q,x<<1,l,mid)) return 1;
		if(R>mid&&queryx(L,R,p,q,x<<1|1,mid+1,r)) return 1;
		return 0;
	}

	void work() {
		for(int i=1;i<=m;i++) insertx(sx[i],sy[i]);
		for(int i=1;i<=n;i++) {
			int l=0,r=4e8;
			while(l<r) {
				int mid=(l+r)>>1;
				int L=lsh_x.find_ge(px[i]-mid),R=lsh_x.find_le(px[i]+mid);
				int p=lsh_y.find_ge(py[i]-mid),q=lsh_y.find_le(py[i]+mid);
				if(queryx(L,R,p,q)) r=mid;
				else l=mid+1;
			}
			dis[i]=l;
		}
	}
}

int main() {
	ios::sync_with_stdio(0);cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		cin>>px[i]>>py[i];
		rotate(px[i],py[i]);
	}
	for(int i=1;i<=m;i++) {
		cin>>sx[i]>>sy[i];
		rotate(sx[i],sy[i]);
		lsh_x.insert(sx[i]);
		lsh_y.insert(sy[i]);
	}
	lsh_x.build();lsh_y.build();
	if(1ll*n*m<=2000000) {
		for(int i=1;i<=n;i++) {
			dis[i]=inf;
			for(int j=1;j<=m;j++) dis[i]=min(dis[i],max(abs(px[i]-sx[j]),abs(py[i]-sy[j])));
		}
	}
	for(int i=1;i<=m;i++) {
		sx[i]=lsh_x.find_ge(sx[i]);
		sy[i]=lsh_y.find_ge(sy[i]);
	}
	if(1ll*n*m>2000000) find_nearest::work();
	int l=0,r=2e8;
	while(l<r) {
		int mid=(l+r)>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l;
	return 0;
}


import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author sheep
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		SoapTime solver = new SoapTime();
		solver.solve(1, in, out);
		out.close();
	}
}

class SoapTime {

    class Point implements Comparable<Point> {
        public int x, y;
        int dist;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        private int sign(int x) {
            return Integer.signum(x);
        }

        public int compareTo(Point arg0) {
            if (x != arg0.x) {
                return sign(x - arg0.x);
            }

            return sign(y - arg0.y);
        }
    }

	public void solve(int testNumber, InputReader in, PrintWriter out) {
        int n = in.nextInt();
        int m = in.nextInt();

        Point man[] = new Point[n];
        Point station[] = new Point[m];

        for (int i = 0; i < n; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            man[i] = new Point((x + y), (x - y));
        }

        for (int i = 0; i < m; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            station[i] = new Point((x + y), (x - y));
        }

        Event events[] = new Event[n + m];
        for (int i = 0; i < n; ++i) {
            events[i] = new Event(man[i].x, man[i].y, i);
        }

        for (int i = 0; i < m; ++i) {
            events[i + n] = new Event(station[i].x, station[i].y);
        }

        int distToStation[] = findDistToStation(events, n);
        for (int i = 0; i < n; ++i) {
            man[i].dist = distToStation[i];
        }

        Arrays.sort(man, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                return o1.dist - o2.dist;
            }
        });

        int low = 0, high = 400000000;
        while (low < high) {
            int mid = (low + high) >> 1;
            if (check(mid, man, station)) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        out.println(low);
	}

    private boolean check(int mid, Point man[], Point station[]) {
        int n = man.length;
        int m = station.length;

        if (man[n - 1].dist <= mid) {
            return true;
        }

        int x1[] = new int[n];
        int y1[] = new int[n];
        int x2[] = new int[n];
        int y2[] = new int[n];

        x1[n - 1] = man[n - 1].x - mid;
        y1[n - 1] = man[n - 1].y - mid;
        x2[n - 1] = man[n - 1].x + mid;
        y2[n - 1] = man[n - 1].y + mid;

        for (int i = n - 2; i >= 0; --i) {
            x1[i] = Math.max(man[i].x - mid, x1[i + 1]);
            x2[i] = Math.min(man[i].x + mid, x2[i + 1]);
            y1[i] = Math.max(man[i].y - mid, y1[i + 1]);
            y2[i] = Math.min(man[i].y + mid, y2[i + 1]);
        }

        if (x1[0] <= x2[0] && y1[0] <= y2[0]) {
            return true;
        }

        Event events[] = new Event[n * 4 + m];
        for (int i = 0; i < n; ++i) {
            events[4 * i + 0] = new Event(x1[i], y1[i], i);
            events[4 * i + 1] = new Event(x1[i], y2[i], i);
            events[4 * i + 2] = new Event(x2[i], y1[i], i);
            events[4 * i + 3] = new Event(x2[i], y2[i], i);
        }

        for (int i = 0; i < m; ++i) {
            events[4 * n + i] = new Event(station[i].x, station[i].y);
        }

        int disStationToRectangle[] = findDistToStation(events, n);

        RectangleEvent rectEvents[] = new RectangleEvent[n + m];
        for (int i = 0; i < n; ++i) {
            rectEvents[i] = new RectangleEvent(x1[i], y1[i], x2[i], y2[i], i);
        }

        for (int i = 0; i < n; ++i) {
            rectEvents[n + i] = new RectangleEvent(station[i].x, station[i].y);
        }

        int disStationToRectangle2[] = findRectangleDistToStation(rectEvents, n);
        for (int i = 0; i < n; ++i) {
            disStationToRectangle[i] = Math.min(disStationToRectangle2[i], disStationToRectangle[i]);
        }

        for (int i = n - 1; i > 0; --i) {
            if (x1[i] <= y1[i] && x2[i] <= y2[i]) {
                if (man[i - 1].dist == Integer.MAX_VALUE || disStationToRectangle[i] == Integer.MAX_VALUE) {
                    continue;
                }

                if (man[i - 1].dist + disStationToRectangle[i] <= mid) {
                    return true;
                }
            }  else {
                break;
            }
        }

        return false;
    }

    private int[] findRectangleDistToStation(RectangleEvent events[], int n) {
        int ret[] = new int[n];
        Arrays.fill(ret, Integer.MAX_VALUE);

        int tmp[] = new int[events.length * 2];

        for (int dir = 0; dir < 4; ++dir) {

            for (int i = 0; i < events.length; ++i) {
                tmp[i * 2] = events[i].x1;
                tmp[i * 2 + 1] = events[i].x2;
            }

            Order order = new Order(tmp);
            for (RectangleEvent e : events) {
                e.realX1 = order.get(e.x1);
                e.realX2 = order.get(e.x2);
            }

            IntervalTree tree = new IntervalTree(order.size());
            Arrays.sort(events);

            for (RectangleEvent e : events) {
                if (e.type == 0) {
                    tree.insert(e.realX1, e.y1);
                } else {
                    int l = Math.min(e.realX1, e.realX2);
                    int r = Math.max(e.realX2, e.realX1);
                    int max = tree.getMaxValue(l, r);
                    if (max == Integer.MIN_VALUE) {
                        continue;
                    }

                    if (max > Math.min(e.y1, e.y2)) {
                        ret[e.updateId] = 0;
                    } else {
                        ret[e.updateId] = Math.min(ret[e.updateId], Math.min(e.y1, e.y2) - max);
                    }
                }
            }

            for (RectangleEvent e : events) {
                e.rotate();
            }
        }

        return ret;
    }

    private int[] findDistToStation(Event events[], int n) {
        int ret[] = new int[n];
        Arrays.fill(ret, Integer.MAX_VALUE);
        int tmp[] = new int[events.length];

        for (int step = 0; step < 4; ++step) {

            int ptr = 0;
            for (Event e : events) {
                tmp[ptr++] = e.x;
            }
            Order order = new Order(tmp);
            for (Event e : events) {
                e.queryX = order.get(e.x);
            }

            IntervalTree tree = new IntervalTree(order.size());
            Arrays.sort(events);

            for (Event e : events) {
                if (e.type == 0) {
                    tree.insert(e.queryX, e.x + e.y);
                } else {
                    int max = tree.getMaxValue(0, e.queryX);
                    if (max == Integer.MIN_VALUE) {
                        continue;
                    }
                    int delta = e.x + e.y - max;
                    if (delta < ret[e.id]) {
                        ret[e.id] = delta;
                    }
                }
            }

            for (Event e : events) {
                int t = e.y;
                e.y = -e.x;
                e.x = t;
            }
        }

        return ret;
    }

    class RectangleEvent implements Comparable<RectangleEvent>{
        int type;
        int x1, y1, x2, y2;
        int realX1, realX2;
        int updateId;

        void rotate() {
            int t = y1;
            y1 = -x1;
            x1 = t;

            t = y2;
            y2 = -x2;
            x2 = t;
        }

        RectangleEvent(int x1, int y1, int x2, int y2, int updateId) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.type = 1;
            this.updateId = updateId;
        }

        RectangleEvent(int x, int y) {
            this.x1 = this.x2 = x;
            this.y1 = this.y2 = y;
            this.type = 0;
        }

        public int compareTo(RectangleEvent o) {
            int y = Math.max(y1, y2);
            int oy = Math.max(o.y1, o.y2);
            if (y != oy) {
                return y - oy;
            }

            int x = Math.max(x1, x2);
            int ox = Math.max(o.x1, o.x2);
            if (x != ox) {
                return x - ox;
            }

            return type - o.type;
        }
    }

    class IntervalTree {

        int size;
        int val[];

        IntervalTree(int length) {
            this.size = length;
            val = new int[length * 4 + 100];
            Arrays.fill(val, Integer.MIN_VALUE);
        }

        int getMaxValue(int left, int right, int l, int r, int x) {
            if (l <= left && r >= right) {
                return val[x];
            }
            int mid = (left + right) >> 1;
            int ret = Integer.MIN_VALUE;
            if (l <= mid) ret = getMaxValue(left, mid, l, r, x * 2);
            if (r > mid) ret = Math.max(ret, getMaxValue(mid + 1, right, l, r, x * 2 + 1));
            return ret;
        }

        int getMaxValue(int left, int right) {
             return getMaxValue(0, size - 1, left, right, 1);
        }

        void insert(int left, int right, int pos, int x, int value) {
            if (left == right) {
                val[x] = Math.max(val[x], value);
                return;
            }

            int mid = (left + right) >> 1;
            if (pos <= mid) {
                insert(left, mid, pos, x * 2, value);
            } else {
                insert(mid + 1, right, pos, x * 2 + 1, value);
            }

            val[x] = Math.max(val[x * 2], val[x * 2 + 1]);
        }

        void insert(int pos, int value) {
             insert(0, size - 1, pos, 1, value);
        }

    }

    class Order {

        private int arr[];

        Order(int orig[]) {
            int temp[] = orig.clone();
            Arrays.sort(temp);

            int total = 1;
            for (int i = 1; i < temp.length; ++i)
                if (temp[i] != temp[i - 1])
                    ++total;

            arr = new int[total];
            arr[0] = temp[0];
            total = 1;
            for (int i = 1; i < temp.length; ++i)
                if (temp[i] != temp[i - 1])
                    arr[total++] = temp[i];
        }

        public int size() {
            return arr.length;
        }

        public int get(int x) {
            return Arrays.binarySearch(arr, x);
        }
    }

    class Event implements Comparable<Event> {
        int type;
        int x, y, id;
        int queryX;

        Event(int x, int y, int id) {
            this.x = x;
            this.y = y;
            this.id = id;
            this.type = 1;
        }

        Event(int x, int y) {
            this.x = x;
            this.y = y;
            this.type = 0;
        }

        public int compareTo(Event o) {
            if (y != o.y) {
                return y - o.y;
            }

            if (x != o.x) {
                return x - o.x;
            }

            return type - o.type;
        }
    }
}

class InputReader {
    BufferedReader reader;
    StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream));
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

    }


package Problems;

import Essential.InputReader;

import java.beans.EventSetDescriptor;
import java.io.PrintWriter;
import java.lang.ArrayStoreException;
import java.lang.Comparable;
import java.lang.Integer;
import java.lang.Override;
import java.util.Arrays;
import java.util.Comparator;

public class SoapTime {

    class Point implements Comparable<Point> {
        public int x, y;
        int dist;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        private int sign(int x) {
            return Integer.signum(x);
        }

        @Override
        public int compareTo(Point arg0) {
            if (x != arg0.x) {
                return sign(x - arg0.x);
            }

            return sign(y - arg0.y);
        }
    }

	public void solve(int testNumber, InputReader in, PrintWriter out) {
        int n = in.nextInt();
        int m = in.nextInt();

        Point man[] = new Point[n];
        Point station[] = new Point[m];

        for (int i = 0; i < n; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            man[i] = new Point((x + y), (x - y));
        }

        for (int i = 0; i < m; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            station[i] = new Point((x + y), (x - y));
        }

        Event events[] = new Event[n + m];
        for (int i = 0; i < n; ++i) {
            events[i] = new Event(man[i].x, man[i].y, i);
        }

        for (int i = 0; i < m; ++i) {
            events[i + n] = new Event(station[i].x, station[i].y);
        }

        int distToStation[] = findDistToStation(events, n);
        for (int i = 0; i < n; ++i) {
            man[i].dist = distToStation[i];
        }

        Arrays.sort(man, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                return o1.dist - o2.dist;
            }
        });

     //   for (Point o : man) {
     //       System.err.println("Point :" + o.x + " " + o.y + " " + o.dist);
     //   }

        int low = 0, high = 400000000;
        while (low < high) {
            int mid = (low + high) >> 1;
            if (check(mid, man, station)) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        out.println(low);
	}

    private boolean check(int mid, Point man[], Point station[]) {
        int n = man.length;
        int m = station.length;

        if (man[n - 1].dist <= mid) {
            return true;
        }

        int x1[] = new int[n];
        int y1[] = new int[n];
        int x2[] = new int[n];
        int y2[] = new int[n];

        x1[n - 1] = man[n - 1].x - mid;
        y1[n - 1] = man[n - 1].y - mid;
        x2[n - 1] = man[n - 1].x + mid;
        y2[n - 1] = man[n - 1].y + mid;

        for (int i = n - 2; i >= 0; --i) {
            x1[i] = Math.max(man[i].x - mid, x1[i + 1]);
            x2[i] = Math.min(man[i].x + mid, x2[i + 1]);
            y1[i] = Math.max(man[i].y - mid, y1[i + 1]);
            y2[i] = Math.min(man[i].y + mid, y2[i + 1]);
        }

        if (x1[0] <= x2[0] && y1[0] <= y2[0]) {
            return true;
        }

        Event events[] = new Event[n * 4 + m];
        for (int i = 0; i < n; ++i) {
            events[4 * i + 0] = new Event(x1[i], y1[i], i);
            events[4 * i + 1] = new Event(x1[i], y2[i], i);
            events[4 * i + 2] = new Event(x2[i], y1[i], i);
            events[4 * i + 3] = new Event(x2[i], y2[i], i);
        }

        for (int i = 0; i < m; ++i) {
            events[4 * n + i] = new Event(station[i].x, station[i].y);
        }

        int disStationToRectangle[] = findDistToStation(events, n);

        RectangleEvent rectEvents[] = new RectangleEvent[n + m];
        for (int i = 0; i < n; ++i) {
            rectEvents[i] = new RectangleEvent(x1[i], y1[i], x2[i], y2[i], i);
        }

        for (int i = 0; i < m; ++i) {
            rectEvents[n + i] = new RectangleEvent(station[i].x, station[i].y);
        }

        int disStationToRectangle2[] = findRectangleDistToStation(rectEvents, n);
        for (int i = 0; i < n; ++i) {
            disStationToRectangle[i] = Math.min(disStationToRectangle2[i], disStationToRectangle[i]);
        }

        for (int i = n - 1; i > 0; --i) {
            if (x1[i] <= x2[i] && y1[i] <= y2[i]) {
                if (man[i - 1].dist == Integer.MAX_VALUE || disStationToRectangle[i] == Integer.MAX_VALUE) {
                    continue;
                }

                if (man[i - 1].dist + disStationToRectangle[i] <= mid) {
                    return true;
                }
            }  else {
                break;
            }
        }

        return false;
    }

    private int[] findRectangleDistToStation(RectangleEvent events[], int n) {
        int ret[] = new int[n];
        Arrays.fill(ret, Integer.MAX_VALUE);

        int tmp[] = new int[events.length * 2];

        for (int dir = 0; dir < 4; ++dir) {

            for (int i = 0; i < events.length; ++i) {
                tmp[i * 2] = events[i].x1;
                tmp[i * 2 + 1] = events[i].x2;
            }

            Order order = new Order(tmp);
            for (RectangleEvent e : events) {
                e.realX1 = order.get(e.x1);
                e.realX2 = order.get(e.x2);
            }

            IntervalTree tree = new IntervalTree(order.size());
            Arrays.sort(events);

            for (RectangleEvent e : events) {
                if (e.type == 0) {
                    tree.insert(e.realX1, e.y1);
                } else {
                    int l = Math.min(e.realX1, e.realX2);
                    int r = Math.max(e.realX2, e.realX1);
                    int max = tree.getMaxValue(l, r);
                    if (max == Integer.MIN_VALUE) {
                        continue;
                    }

                    if (max >= Math.min(e.y1, e.y2)) {
                        ret[e.updateId] = 0;
                    } else {
                        ret[e.updateId] = Math.min(ret[e.updateId], Math.min(e.y1, e.y2) - max);
                    }
                }
            }

            for (RectangleEvent e : events) {
                e.rotate();
            }
        }

        return ret;
    }

    private int[] findDistToStation(Event events[], int n) {
        int ret[] = new int[n];
        for (Event e : events) {
            int x = e.x;
            int y = e.y;
            e.x = (x + y);
            e.y = (x - y);
        }
        Arrays.fill(ret, Integer.MAX_VALUE);
        int tmp[] = new int[events.length];

        for (int step = 0; step < 4; ++step) {

            int ptr = 0;
            for (Event e : events) {
                tmp[ptr++] = e.x;
            }
            Order order = new Order(tmp);
            for (Event e : events) {
                e.queryX = order.get(e.x);
            }

            IntervalTree tree = new IntervalTree(order.size());
            Arrays.sort(events);

            for (Event e : events) {
                if (e.type == 0) {
                    tree.insert(e.queryX, e.x + e.y);
                } else {
                    int max = tree.getMaxValue(0, e.queryX);
                    if (max == Integer.MIN_VALUE) {
                        continue;
                    }
                    int delta = (e.x + e.y - max) / 2;
                    if (delta < ret[e.id]) {
                        ret[e.id] = delta;
                    }
                }
            }

            for (Event e : events) {
                int t = e.y;
                e.y = -e.x;
                e.x = t;
            }
        }

        return ret;
    }

    class RectangleEvent implements Comparable<RectangleEvent>{
        int type;
        int x1, y1, x2, y2;
        int realX1, realX2;
        int updateId;

        void rotate() {
            int t = y1;
            y1 = -x1;
            x1 = t;

            t = y2;
            y2 = -x2;
            x2 = t;
        }

        RectangleEvent(int x1, int y1, int x2, int y2, int updateId) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.type = 1;
            this.updateId = updateId;
        }

        RectangleEvent(int x, int y) {
            this.x1 = this.x2 = x;
            this.y1 = this.y2 = y;
            this.type = 0;
        }

        @Override
        public int compareTo(RectangleEvent o) {
            int y = Math.max(y1, y2);
            int oy = Math.max(o.y1, o.y2);
            if (y != oy) {
                return y - oy;
            }

            int x = Math.max(x1, x2);
            int ox = Math.max(o.x1, o.x2);
                if (x != ox) {
                return x - ox;
            }

            return type - o.type;
        }
    }

    class IntervalTree {

        int size;
        int val[];

        IntervalTree(int length) {
            this.size = length;
            val = new int[length * 4 + 100];
            Arrays.fill(val, Integer.MIN_VALUE);
        }

        int getMaxValue(int left, int right, int l, int r, int x) {
            if (l <= left && r >= right) {
                return val[x];
            }
            int mid = (left + right) >> 1;
            int ret = Integer.MIN_VALUE;
            if (l <= mid) ret = getMaxValue(left, mid, l, r, x * 2);
            if (r > mid) ret = Math.max(ret, getMaxValue(mid + 1, right, l, r, x * 2 + 1));
            return ret;
        }

        int getMaxValue(int left, int right) {
             return getMaxValue(0, size - 1, left, right, 1);
        }

        void insert(int left, int right, int pos, int x, int value) {
            if (left == right) {
                val[x] = Math.max(val[x], value);
                return;
            }

            int mid = (left + right) >> 1;
            if (pos <= mid) {
                insert(left, mid, pos, x * 2, value);
            } else {
                insert(mid + 1, right, pos, x * 2 + 1, value);
            }

            val[x] = Math.max(val[x * 2], val[x * 2 + 1]);
        }

        void insert(int pos, int value) {
             insert(0, size - 1, pos, 1, value);
        }

    }

    class Order {

        private int arr[];

        Order(int orig[]) {
            int temp[] = orig.clone();
            Arrays.sort(temp);

            int total = 1;
            for (int i = 1; i < temp.length; ++i)
                if (temp[i] != temp[i - 1])
                    ++total;

            arr = new int[total];
            arr[0] = temp[0];
            total = 1;
            for (int i = 1; i < temp.length; ++i)
                if (temp[i] != temp[i - 1])
                    arr[total++] = temp[i];
        }

        public int size() {
            return arr.length;
        }

        public int get(int x) {
            return Arrays.binarySearch(arr, x);
        }
    }

    class Event implements Comparable<Event> {
        int type;
        int x, y, id;
        int queryX;

        Event(int x, int y, int id) {
            this.x = x;
            this.y = y;
            this.id = id;
            this.type = 1;
        }

        Event(int x, int y) {
            this.x = x;
            this.y = y;
            this.type = 0;
        }

        @Override
        public int compareTo(Event o) {
            if (y != o.y) {
                return y - o.y;
            }

            if (x != o.x) {
                return x - o.x;
            }

            return type - o.type;
        }
    }
}


import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author sheep
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		SoapTime solver = new SoapTime();
		solver.solve(1, in, out);
		out.close();
	}
}

class SoapTime {

    class Point implements Comparable<Point> {
        public int x, y;
        int dist;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        private int sign(int x) {
            return Integer.signum(x);
        }

        public int compareTo(Point arg0) {
            if (x != arg0.x) {
                return sign(x - arg0.x);
            }

            return sign(y - arg0.y);
        }
    }

	public void solve(int testNumber, InputReader in, PrintWriter out) {
        int n = in.nextInt();
        int m = in.nextInt();

        Point man[] = new Point[n];
        Point station[] = new Point[m];

        for (int i = 0; i < n; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            man[i] = new Point((x + y), (x - y));
        }

        for (int i = 0; i < m; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            station[i] = new Point((x + y), (x - y));
        }

        Event events[] = new Event[n + m];
        for (int i = 0; i < n; ++i) {
            events[i] = new Event(man[i].x, man[i].y, i);
        }

        for (int i = 0; i < m; ++i) {
            events[i + n] = new Event(station[i].x, station[i].y);
        }

        int distToStation[] = findDistToStation(events, n);
        for (int i = 0; i < n; ++i) {
            man[i].dist = distToStation[i];
        }

        Arrays.sort(man, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                return o1.dist - o2.dist;
            }
        });

        int low = 0, high = 400000000;
        while (low < high) {
            int mid = (low + high) >> 1;
            if (check(mid, man, station)) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        out.println(low);
	}

    private boolean check(int mid, Point man[], Point station[]) {
        int n = man.length;
        int m = station.length;

        if (man[n - 1].dist <= mid) {
            return true;
        }

        int x1[] = new int[n];
        int y1[] = new int[n];
        int x2[] = new int[n];
        int y2[] = new int[n];

        x1[n - 1] = man[n - 1].x - mid;
        y1[n - 1] = man[n - 1].y - mid;
        x2[n - 1] = man[n - 1].x + mid;
        y2[n - 1] = man[n - 1].y + mid;

        for (int i = n - 2; i >= 0; --i) {
            x1[i] = Math.max(man[i].x - mid, x1[i + 1]);
            x2[i] = Math.min(man[i].x + mid, x2[i + 1]);
            y1[i] = Math.max(man[i].y - mid, y1[i + 1]);
            y2[i] = Math.min(man[i].y + mid, y2[i + 1]);
        }

        if (x1[0] <= x2[0] && y1[0] <= y2[0]) {
            return true;
        }

        Event events[] = new Event[n * 4 + m];
        for (int i = 0; i < n; ++i) {
            events[4 * i + 0] = new Event(x1[i], y1[i], i);
            events[4 * i + 1] = new Event(x1[i], y2[i], i);
            events[4 * i + 2] = new Event(x2[i], y1[i], i);
            events[4 * i + 3] = new Event(x2[i], y2[i], i);
        }

        for (int i = 0; i < m; ++i) {
            events[4 * n + i] = new Event(station[i].x, station[i].y);
        }

        int disStationToRectangle[] = findDistToStation(events, n);

        RectangleEvent rectEvents[] = new RectangleEvent[n + m];
        for (int i = 0; i < n; ++i) {
            rectEvents[i] = new RectangleEvent(x1[i], y1[i], x2[i], y2[i], i);
        }

        for (int i = 0; i < m; ++i) {
            rectEvents[n + i] = new RectangleEvent(station[i].x, station[i].y);
        }

        int disStationToRectangle2[] = findRectangleDistToStation(rectEvents, n);
        for (int i = 0; i < n; ++i) {
            disStationToRectangle[i] = Math.min(disStationToRectangle2[i], disStationToRectangle[i]);
        }

        for (int i = n - 1; i > 0; --i) {
            if (x1[i] <= y1[i] && x2[i] <= y2[i]) {
                if (man[i - 1].dist == Integer.MAX_VALUE || disStationToRectangle[i] == Integer.MAX_VALUE) {
                    continue;
                }

                if (man[i - 1].dist + disStationToRectangle[i] <= mid) {
                    return true;
                }
            }  else {
                break;
            }
        }

        return false;
    }

    private int[] findRectangleDistToStation(RectangleEvent events[], int n) {
        int ret[] = new int[n];
        Arrays.fill(ret, Integer.MAX_VALUE);

        int tmp[] = new int[events.length * 2];

        for (int dir = 0; dir < 4; ++dir) {

            for (int i = 0; i < events.length; ++i) {
                tmp[i * 2] = events[i].x1;
                tmp[i * 2 + 1] = events[i].x2;
            }

            Order order = new Order(tmp);
            for (RectangleEvent e : events) {
                e.realX1 = order.get(e.x1);
                e.realX2 = order.get(e.x2);
            }

            IntervalTree tree = new IntervalTree(order.size());
            Arrays.sort(events);

            for (RectangleEvent e : events) {
                if (e.type == 0) {
                    tree.insert(e.realX1, e.y1);
                } else {
                    int l = Math.min(e.realX1, e.realX2);
                    int r = Math.max(e.realX2, e.realX1);
                    int max = tree.getMaxValue(l, r);
                    if (max == Integer.MIN_VALUE) {
                        continue;
                    }

                    if (max >= Math.min(e.y1, e.y2)) {
                        ret[e.updateId] = 0;
                    } else {
                        ret[e.updateId] = Math.min(ret[e.updateId], Math.min(e.y1, e.y2) - max);
                    }
                }
            }

            for (RectangleEvent e : events) {
                e.rotate();
            }
        }

        return ret;
    }

    private int[] findDistToStation(Event events[], int n) {
        int ret[] = new int[n];
        for (Event e : events) {
            int x = e.x;
            int y = e.y;
            e.x = (x + y) / 2;
            e.y = (x - y) / 2;
        }
        Arrays.fill(ret, Integer.MAX_VALUE);
        int tmp[] = new int[events.length];

        for (int step = 0; step < 4; ++step) {

            int ptr = 0;
            for (Event e : events) {
                tmp[ptr++] = e.x;
            }
            Order order = new Order(tmp);
            for (Event e : events) {
                e.queryX = order.get(e.x);
            }

            IntervalTree tree = new IntervalTree(order.size());
            Arrays.sort(events);

            for (Event e : events) {
                if (e.type == 0) {
                    tree.insert(e.queryX, e.x + e.y);
                } else {
                    int max = tree.getMaxValue(0, e.queryX);
                    if (max == Integer.MIN_VALUE) {
                        continue;
                    }
                    int delta = e.x + e.y - max;
                    if (delta < ret[e.id]) {
                        ret[e.id] = delta;
                    }
                }
            }

            for (Event e : events) {
                int t = e.y;
                e.y = -e.x;
                e.x = t;
            }
        }

        return ret;
    }

    class RectangleEvent implements Comparable<RectangleEvent>{
        int type;
        int x1, y1, x2, y2;
        int realX1, realX2;
        int updateId;

        void rotate() {
            int t = y1;
            y1 = -x1;
            x1 = t;

            t = y2;
            y2 = -x2;
            x2 = t;
        }

        RectangleEvent(int x1, int y1, int x2, int y2, int updateId) {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.type = 1;
            this.updateId = updateId;
        }

        RectangleEvent(int x, int y) {
            this.x1 = this.x2 = x;
            this.y1 = this.y2 = y;
            this.type = 0;
        }

        public int compareTo(RectangleEvent o) {
            int y = Math.max(y1, y2);
            int oy = Math.max(o.y1, o.y2);
            if (y != oy) {
                return y - oy;
            }

            int x = Math.max(x1, x2);
            int ox = Math.max(o.x1, o.x2);
            if (x != ox) {
                return x - ox;
            }

            return type - o.type;
        }
    }

    class IntervalTree {

        int size;
        int val[];

        IntervalTree(int length) {
            this.size = length;
            val = new int[length * 4 + 100];
            Arrays.fill(val, Integer.MIN_VALUE);
        }

        int getMaxValue(int left, int right, int l, int r, int x) {
            if (l <= left && r >= right) {
                return val[x];
            }
            int mid = (left + right) >> 1;
            int ret = Integer.MIN_VALUE;
            if (l <= mid) ret = getMaxValue(left, mid, l, r, x * 2);
            if (r > mid) ret = Math.max(ret, getMaxValue(mid + 1, right, l, r, x * 2 + 1));
            return ret;
        }

        int getMaxValue(int left, int right) {
             return getMaxValue(0, size - 1, left, right, 1);
        }

        void insert(int left, int right, int pos, int x, int value) {
            if (left == right) {
                val[x] = Math.max(val[x], value);
                return;
            }

            int mid = (left + right) >> 1;
            if (pos <= mid) {
                insert(left, mid, pos, x * 2, value);
            } else {
                insert(mid + 1, right, pos, x * 2 + 1, value);
            }

            val[x] = Math.max(val[x * 2], val[x * 2 + 1]);
        }

        void insert(int pos, int value) {
             insert(0, size - 1, pos, 1, value);
        }

    }

    class Order {

        private int arr[];

        Order(int orig[]) {
            int temp[] = orig.clone();
            Arrays.sort(temp);

            int total = 1;
            for (int i = 1; i < temp.length; ++i)
                if (temp[i] != temp[i - 1])
                    ++total;

            arr = new int[total];
            arr[0] = temp[0];
            total = 1;
            for (int i = 1; i < temp.length; ++i)
                if (temp[i] != temp[i - 1])
                    arr[total++] = temp[i];
        }

        public int size() {
            return arr.length;
        }

        public int get(int x) {
            return Arrays.binarySearch(arr, x);
        }
    }

    class Event implements Comparable<Event> {
        int type;
        int x, y, id;
        int queryX;

        Event(int x, int y, int id) {
            this.x = x;
            this.y = y;
            this.id = id;
            this.type = 1;
        }

        Event(int x, int y) {
            this.x = x;
            this.y = y;
            this.type = 0;
        }

        public int compareTo(Event o) {
            if (y != o.y) {
                return y - o.y;
            }

            if (x != o.x) {
                return x - o.x;
            }

            return type - o.type;
        }
    }
}

class InputReader {
    BufferedReader reader;
    StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream));
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

    public int nextInt() {
        return Integer.parseInt(next());
    }

    }