bzoj 2716: [Violet 3]天使玩偶(cdq分治)
2016-09-10 19:54
357 查看
2716: [Violet 3]天使玩偶
Time Limit: 80 Sec Memory Limit: 128 MBSubmit: 1231 Solved: 541
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
100 10081 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
38
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);
}
相关文章推荐
- BZOJ 2716 Violet 3 天使玩偶 CDQ分治
- bzoj2716 [Violet 3]天使玩偶(CDQ分治)
- BZOJ.2716.[Violet3]天使玩偶(CDQ分治 坐标变换)
- BZOJ2716 [Violet 3]天使玩偶 【CDQ分治】
- BZOJ 2716 Violet 3 天使玩偶 CDQ分治
- BZOJ 2716: [Violet 3]天使玩偶( CDQ分治 + 树状数组 )
- BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]
- BZOJ 2716: [Violet 3]天使玩偶 | CDQ分治
- bzoj 2716 [Violet 3]天使玩偶 【CDQ分治】
- [BZOJ2716][Violet 3]天使玩偶(cdq分治||KD-tree)
- [BZOJ2716][天使玩偶angel][CDQ分治]
- bzoj 2716 天使玩偶(CDQ分治,BIT)
- [bzoj] 2716 天使玩偶 || CDQ分治
- BZOJ 2648 SJY摆棋子 / 2716 Violet 3 天使玩偶 K-D树
- 【Violet3】【BZOJ2716】天使玩偶
- bzoj2716 [Violet 3]天使玩偶(KDtree)
- BZOJ2716 [Violet]天使玩偶(cdq分治+树状数组)
- BZOJ 2716 [Violet 3]天使玩偶 KDtree
- [BZOJ2716][Violet 3]天使玩偶 && kdtree
- BZOJ 2716 [Violet 3]天使玩偶