//首先有一个比较重要的性质
//那就是答案矩形一定经过直线x=w/2或直线y=h/2
//因为答案下界是2*(max(h,w)+1)，观察易得。
//然后我们就有一个比较好的n^2做法
//也就是在枚举的L和R之间找 大于h/2且最小的U 与 小于等于h/2且最大的D
//此时的U和D就是L,R作为边界之一时的最优答案
//另一个方向也是这么做。
//考虑增量法更新答案。
//我们不难发现随着R增加，每一个L对应的U是只降不增的，D是只增不降的
//而且随着L的增大，每一个R对应的U和D也有类似的性质
//考虑每次移动R的时候，更新所有L的答案
//那么我们只需要两个单调栈分别维护所有L的U与D。
//然后用线段树区间修改+查询max即可 
//详细看题解+代码 
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define N 300005
using namespace std;
int w,h,n,ans;
struct Point
{
	int x,y;
}p[N];
int cmp1(Point a,Point b)
{
	return a.x<b.x;
}
int cmp2(Point a,Point b)
{
	return a.y<b.y;
}
struct node
{
	int l,r,v;
};
vector<node>st1,st2;
int maxn[4*N],tag[4*N];
inline void Add(int k,int v)
{
	maxn[k]+=v,tag[k]+=v;
}
inline void down(int k)
{
	if(!tag[k])return;
	Add(k*2,tag[k]);
	Add(k*2+1,tag[k]);
	tag[k]=0;
}
void change(int k,int l,int r,int x,int y,int v)
{
	if(x<=l&&r<=y)
	{
		Add(k,v);
		return;
	}
	int mid=(l+r)>>1;
	down(k);
	if(x<=mid)change(k*2,l,mid,x,y,v);
	if(y>mid)change(k*2+1,mid+1,r,x,y,v);
	maxn[k]=max(maxn[k*2],maxn[k*2+1]);
}
int Ask(int k,int l,int r,int x,int y)
{
	if(x<=l&&r<=y)return maxn[k];
	int mid=(l+r)>>1;
	down(k);
	int temp=-1e9;
	if(x<=mid)temp=max(temp,Ask(k*2,l,mid,x,y));
	if(y>mid)temp=max(temp,Ask(k*2+1,mid+1,r,x,y));
	maxn[k]=max(maxn[k*2],maxn[k*2+1]);
	return temp;
}
int main()
{
//	freopen("paint3.in","r",stdin);
	scanf("%d %d %d",&w,&h,&n);
	for(int i=1;i<=n;i++)
		scanf("%d %d",&p[i].x,&p[i].y);
	p[++n]=(Point){0,0};
	p[++n]=(Point){w,h};
	sort(p+1,p+1+n,cmp1);
	for(int i=1;i<=n;i++)
	{
		int maxn=h,minn=0;
		if(p[i].y<=h/2)minn=max(minn,p[i].y);
		else maxn=max(minn,p[i].y);
		while(i<n&&p[i].x==p[i+1].x)
		{
			i++;
			if(p[i].y<=h/2)minn=max(minn,p[i].y);
			else maxn=max(minn,p[i].y);
		}
		if(i!=1)ans=max(ans,p[i].x+Ask(1,1,n,1,i-1));
		change(1,1,n,i,i,-p[i].x+h-0);
		
		int L=i,R=i-1;
		while(!st1.empty()&&st1.back().v>=maxn)
		{
			change(1,1,n,st1.back().l,st1.back().r,-st1.back().v);
			L=st1.back().l;
			st1.pop_back();
		}
		if(L<=R)st1.push_back((node){L,R,maxn}),change(1,1,n,L,R,maxn);
		st1.push_back((node){i,i,h});
		
		L=i,R=i-1;
		while(!st2.empty()&&st2.back().v<=minn)
		{
			change(1,1,n,st2.back().l,st2.back().r,st2.back().v);
			L=st2.back().l;
			st2.pop_back();
		}
		if(L<=R)st2.push_back((node){L,R,minn}),change(1,1,n,L,R,-minn);
		st2.push_back((node){i,i,0});
	}
	memset(tag,0,sizeof(tag));
	memset(maxn,0,sizeof(maxn));
	st1.clear(),st2.clear();
	sort(p+1,p+1+n,cmp2);
	for(int i=1;i<=n;i++)
	{
		int maxn=w,minn=0;
		if(p[i].x<=h/2)minn=max(minn,p[i].x);
		else maxn=max(minn,p[i].x);
		while(i<n&&p[i].y==p[i+1].y)
		{
			i++;
			if(p[i].x<=w/2)minn=max(minn,p[i].x);
			else maxn=max(minn,p[i].x);
		}
		if(i!=1)ans=max(ans,p[i].y+Ask(1,1,n,1,i-1));
		change(1,1,n,i,i,-p[i].y+w-0);
		
		int L=i,R=i-1;
		while(!st1.empty()&&st1.back().v>=maxn)
		{
			change(1,1,n,st1.back().l,st1.back().r,-st1.back().v);
			L=st1.back().l;
			st1.pop_back();
		}
		if(L<=R)st1.push_back((node){L,R,maxn}),change(1,1,n,L,R,maxn);
		st1.push_back((node){i,i,w});
		
		L=i,R=i-1;
		while(!st2.empty()&&st2.back().v<=minn)
		{
			change(1,1,n,st2.back().l,st2.back().r,st2.back().v);
			L=st2.back().l;
			st2.pop_back();
		}
		if(L<=R)st2.push_back((node){L,R,minn}),change(1,1,n,L,R,-minn);
		st2.push_back((node){i,i,0});
	}
	printf("%d\n",2*ans);
	return 0;
}

Measured memory_bytes: 14260