您的位置:首页 > 其它

bzoj 2716: [Violet 3]天使玩偶(cdq分治)

2016-09-10 19:54 357 查看

2716: [Violet 3]天使玩偶

Time Limit: 80 Sec  Memory Limit: 128 MB
Submit: 1231  Solved: 541

[Submit][Status][Discuss]

Description



Input



Output



Sample Input

100 100

81 23

27 16

52 58

44 24

25 95

34 2

96 25

8 14

97 50

97 18

64 3

47 22

55 28

89 37

75 45

67 22

90 8

65 45

68 93

87 8

61 45

69 72

38 57

58 76

45 34

88 54

27 8

35 34

70 81

25 24

97 97

4 43

39 38

82 68

27 58

2 21

92 88

96 70

97 29

14 53

6 42

1 2

35 84

64 88

63 57

53 40

82 59

49 56

75 72

29 30

50 1

40 83

52 94

22 35

39 1

94 88

89 96

79 46

33 75

31 42

33 95

6 83

90 66

37 54

35 64

17 66

48 37

30 8

95 51

3 51

90 33

29 48

94 78

53 7

1 26

73 35

18 33

99 78

83 59

23 87

4 17

53 91

98 3

54 82

85 92

77 8

56 74

4 5

63 1

26 8

42 15

48 98

27 11

70 98

36 9

78 92

34 40

42 82

64 83

75 47

2 51 55

1 7 62

2 21 62

1 36 39

1 35 89

1 84 15

2 19 24

1 58 53

2 52 34

1 98 49

1 4 100

1 17 25

1 30 56

1 69 43

2 57 23

2 23 13

1 98 25

2 50 27

1 84 63

2 84 81

2 84 77

1 60 23

2 15 27

1 9 51

1 31 11

1 96 56

2 20 85

1 46 32

1 60 88

2 92 48

1 68 5

2 90 17

1 16 46

2 67 5

2 29 83

1 84 70

2 68 27

1 99 33

2 39 89

2 38 28

1 42 3

1 10 60

2 56 29

2 12 60

2 46 51

2 15 73

1 93 42

1 78 82

1 66 20

1 46 17

2 48 5

1 59 61

1 87 59

2 98 72

1 49 3

2 21 10

1 15 4

1 48 14

2 67 75

2 83 77

1 88 65

2 100 93

2 58 83

1 29 80

2 31 88

2 92 94

1 96 66

1 61 82

2 87 24

1 64 83

1 28 87

2 72 90

2 7 3

1 86 3

2 26 53

2 71 2

2 88 24

1 69 60

1 92 44

2 74 94

1 12 78

2 1 2

1 4 73

1 58 5

1 62 14

2 64 58

2 39 45

1 99 27

1 42 21

1 87 2

2 16 98

2 17 21

2 41 20

1 46 72

1 11 62

2 68 29

1 64 66

2 90 42

2 63 35

1 64 71

Sample Output

3

8

6

7

7

6

6

12

11

4

5

6

8

1

7

6

4

9

2

2

8

9

6

4

7

5

8

7

5

5

5

7

7

5

6

6

8

6

0

2

7

12

4

2

8

3

10

HINT



Source

Vani原创
欢迎移步 OJ2648

[Submit][Status][Discuss]

题解:cdq分治

这道题就是求平面最近点对(曼哈顿距离最短),同时支持动态加点。

dis=|x-x'|+|y-y'|,我们考虑左下角的点,则dis=(x+y)-(x'+y')。

那么我们其实就是求询问前左下角的点中(x'+y')的最大值。

于是我们考虑cdq分治。

先把所有的点按照x坐标排序,然后二分操作的序号,将操作分成两部分,前一部分的操作标号为[l,mid],后一部分的操作编号为[mid+1,r]。并且这两部分中的点在所属的部分内x坐标有序。

在统计答案的时候我们保证横坐标有序,将(x+y)的值扔到对应纵坐标的树状数组中。

[l,mid]中的点会对[mid+1,r]中的点产生影响,我们用两个指针指到两部分的开头,通过指针后移,保证后一部分中的点计算答案时前一部分中横坐标小于等于该点的点已经加入树状数组中,然后不断更新答案即可。

这是左下角的情况,那么剩下的四个角怎么办呢?

我们通过坐标对称的方式将点的位置进行转换,关于x轴对称,关于y轴对称,关于原点对称。注意对称后要保证坐标为正数。这样原本在不在左下角的点都会有机会变换到左下角。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 1000003
#define M 3000010
using namespace std;
int n,m,tr[M],maxn;
struct data
{
int x,y,num,pd,mark,ans;
bool operator <(const data &a)const
{
return x<a.x||x==a.x&&mark<a.mark;
}
}a
,p
;
int cmp1(data a,data b)
{
return a.num<b.num;
}
int cmp(data a,data b)
{
return a.x<b.x||a.x==b.x&&a.mark<b.mark;
}
int lowbit(int x)
{
return x&(-x);
}
void clear(int x)
{
for (int i=x;i<=maxn;i+=lowbit(i))
tr[i]=-1;
}
void change(int x,int k)
{
for (int i=x;i<=maxn;i+=lowbit(i))
tr[i]=max(tr[i],k);
}
int qjmax(int x)
{
int ans=-1;
for (int i=x;i>=1;i-=lowbit(i))
ans=max(ans,tr[i]);
return ans;
}
void divide(int l,int r)
{
if (l==1&&r==m)
memset(tr,-1,sizeof(tr));
if (l==r) return;
int mid=(l+r)/2;
int l1=l; int l2=mid+1;
for (int i=l;i<=r;i++)
if (a[i].num<=mid) p[l1++]=a[i];
else p[l2++]=a[i];
for (int i=l;i<=r;i++) a[i]=p[i];
int i=mid+1; int j=l;
for ( ;i<=r;i++)
if (a[i].mark==2)
{
for (;j<=mid&&a[j].x<=a[i].x;j++)
if (a[j].mark==1) change(a[j].y,a[j].x+a[j].y);
int t=qjmax(a[i].y);
if (t!=-1)
a[i].ans=min(a[i].ans,a[i].x+a[i].y-t);
}
for (int i=l;i<j;i++) if(a[i].mark==1) clear(a[i].y);
divide(l,mid);
divide(mid+1,r);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y); a[i].x++; a[i].y++;
a[i].num=i; a[i].mark=1; maxn=max(maxn,a[i].y); maxn=max(maxn,a[i].x);
a[i].ans=M*3;
}
m+=n;
for (int i=n+1;i<=m;i++)
{
scanf("%d%d%d",&a[i].mark,&a[i].x,&a[i].y); a[i].x++; a[i].y++;
a[i].num=i; maxn=max(maxn,a[i].y); maxn=max(maxn,a[i].x);
a[i].ans=M*3;
}
sort(a+1,a+m+1,cmp);
maxn++;
divide(1,m);
for (int i=1;i<=m;i++)
a[i].x=-a[i].x+maxn;
sort(a+1,a+m+1,cmp);
divide(1,m);
for (int i=1;i<=m;i++)
a[i].y=-a[i].y+maxn;
sort(a+1,a+m+1,cmp);
divide(1,m);
for (int i=1;i<=m;i++)
a[i].x=-(a[i].x-maxn);
sort(a+1,a+m+1,cmp);
divide(1,m);
for (int i=1;i<=m;i++)
a[i].y=-(a[i].y-maxn);
sort(a+1,a+m+1,cmp1);
for (int i=1;i<=m;i++)
if (a[i].mark==2)
printf("%d\n",a[i].ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: