Description
长跑的目的不是更快,而是更强。 ——zjp’s blog
zjp最近迷上了长跑。为了防止被zjp强锋吹拂,小狗们决定躲到狗窝里去,现在已知有n条狗在一个二维平面直角坐标系的第一象限内。
狗是一种特殊的生物,每只在(x, y)的狗走一步只能到达(x + y, y),(x, y +x),(x − y, y),(x, y − x)这四个位置中的任意一个。并且任何时候,狗都不能在坐标轴上或在到达其它象限内的位置。
每个狗窝只能容纳一条狗,我们知道n个狗窝的坐标(也在第一象限内),每条狗不一定要到其对应编号的狗窝。
经过狗精密的计算发现,当所有狗到达狗窝的步数和最小时,狗是最安全的,尽管有的狗可能要走较多的步数。
现在,你只需要告诉他们:所有狗都到达狗窝的最小步数和。
Input
从文件a.in中读入数据.
第一行,包含一个正整数n,表示狗以及狗窝数。
接下来n行,每行包含两个正整数,表示每只狗的最初位置。
接下来n行,每行包含两个正整数,表示每个狗窝的位置。
Output
输出到文件a.out中.
仅包含一行,一个整数,表示所有狗都到达狗窝的最小步数和。
Sample Input1
1
203 235
481 171
Sample Input2
2
1 2
4 7
3 2
7 3
Sample Output1
6
Sample Output2
3
Data Constraint
对于所有数据,有
n
≤
5
×
1
0
4
n ≤ 5 × 10^4
n≤5×104,坐标范围
≤
1
0
18
≤10^{18}
≤1018,保证任意一对狗和狗窝可达。
设最远的一对狗和狗窝相距m步。
• 对于10%的数据:
n
=
1
,
1
≤
m
≤
14
n = 1,1 ≤ m ≤ 14
n=1,1≤m≤14
• 对于30%的数据:
n
=
1
,
1
≤
m
≤
500
n = 1,1 ≤ m ≤ 500
n=1,1≤m≤500
• 对于50%的数据:
n
≤
200
,
1
≤
m
≤
500
n ≤ 200,1 ≤ m ≤ 500
n≤200,1≤m≤500
• 对于70%的数据:
n
≤
1
0
4
,
1
≤
m
≤
500
n ≤ 10^4,1 ≤ m ≤ 500
n≤104,1≤m≤500
• 对于最后30%的数据,没有特殊的约定
分析:
显然一个点只有
3
3
3中变化。
我们设
x
>
y
x>y
x>y,这三种变化分别为
(
x
+
y
,
y
)
(x+y,y)
(x+y,y),
(
x
,
x
+
y
)
(x,x+y)
(x,x+y),
(
x
−
y
,
y
)
(x-y,y)
(x−y,y)。
我们把加的看作是这个点的两个儿子,减得看做父亲,发现这是一棵二叉树,根节点的坐标为
(
g
c
d
(
x
,
y
)
,
g
c
d
(
x
,
y
)
)
(gcd(x,y),gcd(x,y))
(gcd(x,y),gcd(x,y))。
70分就直接把路径上的点标出来,然后把所有点连成一棵树,然后树上统计即可,计算答案是比较简单的。
100分就是要保留一些关键点,这些关键点就是直接对
(
x
,
y
)
(x,y)
(x,y)进行辗转相除的那些点。
当我们发现一对
(
x
′
,
y
′
)
(x',y')
(x′,y′)已经出现过,就把这个信息挂在这个点上,注意分类,然后从小到大连上即可。
我的程序直接暴力动态修改,就是暴力跳儿子直到权值介于父亲和儿子之间,这样强行卡过了。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
#define LL long long
const int maxn=2e6+7;
using namespace std;
int n,m,root,cnt;
int sum[maxn];
LL ans,x,y;
struct rec{
LL x,y;
};
bool operator <(rec a,rec b)
{
if (a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
struct node{
int l,r,op;
LL x,y;
LL len1,len2;
}t[maxn];
map <rec,int> num;
int getabs(int x)
{
if (x>0) return x;
return -x;
}
void updata(int x)
{
if (t[x].l) t[x].len1=(t[t[x].l].x-t[x].x)/t[t[x].l].y;
if (t[x].r) t[x].len2=(t[t[x].r].y-t[x].y)/t[t[x].r].x;
}
void build(LL S,LL T,int d)
{
int e=num[(rec){S,T}];
if (e)
{
t[e].op+=d;
return;
}
LL x=S,y=T,lastx=0,lasty=0;
int op;
while (!num[(rec){x,y}])
{
num[(rec){x,y}]=++cnt;
t[cnt].x=x,t[cnt].y=y;
if (lastx)
{
if (op==0) t[cnt].l=cnt-1;
else t[cnt].r=cnt-1;
updata(cnt);
}
if (x==y) break;
lastx=x,lasty=y;
if (x>y) x%=y,op=0;
else y%=x,op=1;
if (!x) x=y;
if (!y) y=x;
}
t[num[(rec){S,T}]].op+=d;
int c=num[(rec){x,y}];
while (true)
{
int last=c;
if ((op==0) && (t[c].l) && (t[t[c].l].x<lastx)) c=t[c].l;
if ((op==1) && (t[c].r) && (t[t[c].r].y<lasty)) c=t[c].r;
if (c==last) break;
}
if (op==0)
{
int p=c,q=t[p].l;
t[p].l=cnt;
if (q) t[cnt].l=q;
updata(cnt),updata(p);
}
else
{
int p=c,q=t[p].r;
t[p].r=cnt;
if (q) t[cnt].r=q;
updata(cnt),updata(p);
}
}
void dfs(int x)
{
if (t[x].l)
{
dfs(t[x].l);
ans+=(LL)abs(sum[t[x].l])*t[x].len1;
sum[x]+=sum[t[x].l];
}
if (t[x].r)
{
dfs(t[x].r);
ans+=(LL)abs(sum[t[x].r])*t[x].len2;
sum[x]+=sum[t[x].r];
}
sum[x]+=t[x].op;
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld%lld",&x,&y);
build(x,y,1);
if (!root) root=cnt;
}
for (int i=1;i<=n;i++)
{
scanf("%lld%lld",&x,&y);
build(x,y,-1);
}
dfs(root);
printf("%lld",ans);
}