您的位置:首页 > 其它

【bzoj 2716】[Violet 3]天使玩偶 (cdq分治+树状数组)

2016-09-11 09:25 417 查看

2716: [Violet 3]天使玩偶

Time Limit: 80 Sec  Memory Limit: 128 MB
Submit: 1241  Solved: 546

[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分治】

【这道题,看看时限差点弃了。。。然而还好,卡过了】

【上来觉得,和Mokia差不多,只是把求和改成求最大值。实际也确实是这样。】

【这道题考虑每个点的周围四个方向上的点(左下、左上、右下、右上)时不能放在一起讨论,不然就没办法分治了。所以每个点每次只考虑一个方向,做四次(赶脚时间会很可怕啊。。。)d=|x-x'|+|y-y'|,当在左下时,d=x+y-(x'+y'),这时只需查找(x'+y')最大即可,依然以x为关键字排序,以y为下标维护树状数组,每次查找最大值。  由于左下位置是最好考虑的,那么我们考虑把另三个方向通过轴对称变换改变其与当前点的相对位置,将它们搞到左下来再处理】

【其实这道题最大的问题在于如何优化时间,如果按照上两道题的方法,每次分治到一个区间就重新把左右区间排序,那么时间上肯定不允许,毕竟按照这种方法,在每次改变点的相对位置后,还需要把操作的顺序归为初始,这样就坐等TLE吧。。。 实际上,我们可以每次分治前,把整个操作序列按x为关键字排序,然后再分治到每一区间时,调整这个区间的操作顺序,这样就可以缩短时间】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct slove{
int x,y,num,nm;
int opt;
}a[1000010],p[1000010];
int ans[1000010],tree[1000010];
int n,m,cnt,mod,tot;

int tmp(slove a,slove b)
{
return a.x<b.x||a.x==b.x&&a.opt<b.opt;
}
int cmp(slove a,slove b)
{
return a.num<b.num;
}

inline int lowbit(int x)
{
return x&(-x);
}
inline void add(int x,int val)
{
while(x<=mod)
{
if(tree[x]<val) tree[x]=val;
x+=lowbit(x);
}
return;
}
inline int ask(int x)
{
int ss=0;
while(x)
{
if(ss<tree[x]) ss=tree[x];
x-=lowbit(x);
}
return ss;
}
inline void clear(int x,int val)
{
while(x<=mod)
{
tree[x]=val;
x+=lowbit(x);
}
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
int tl=l,tr=mid+1;
for(int i=l;i<=r;++i)
if(a[i].num<=mid) p[tl++]=a[i];
else p[tr++]=a[i];
for(int i=l;i<=r;++i) a[i]=p[i];
int j=l;
for(int i=mid+1;i<=r;++i)
if(a[i].opt==2)
{
while(j<=mid&&a[j].x<=a[i].x)
{
if(a[j].opt==1) add(a[j].y,a[j].x+a[j].y);
++j;
}
int t=ask(a[i].y);
if(t)
{
t=a[i].x+a[i].y-t;
if(t<ans[a[i].nm]) ans[a[i].nm]=t;
}
}
for(int i=l;i<j;++i)
if(a[i].opt==1) clear(a[i].y,0);
cdq(l,mid); cdq(mid+1,r);
}
int main()
{
int i;
scanf("%d%d",&n,&m);
memset(ans,127,sizeof(ans));
for(i=1;i<=n;++i)
{
++cnt;
int xx,yy;
scanf("%d%d",&xx,&yy);
a[cnt].x=++xx; a[cnt].y=++yy;
a[cnt].opt=1; a[cnt].num=cnt;
if(yy>mod) mod=yy; if(xx>mod) mod=xx;
}
for(i=1;i<=m;++i)
{
++cnt;
int xx,yy;
scanf("%d%d%d",&a[cnt].opt,&xx,&yy);
a[cnt].x=++xx; a[cnt].y=++yy; a[cnt].num=cnt;
if(a[cnt].opt==2) a[cnt].nm=++tot;
if(yy>mod) mod=yy; if(xx>mod) mod=xx;
}
mod++;
sort(a+1,a+cnt+1,tmp);
cdq(1,cnt);//查找左下
for(i=1;i<=cnt;++i) a[i].x=-a[i].x+mod;
sort(a+1,a+cnt+1,tmp);
cdq(1,cnt);//查找左上
for(i=1;i<=cnt;++i) a[i].y=-a[i].y+mod;
sort(a+1,a+cnt+1,tmp);
cdq(1,cnt);//查找右下
for(i=1;i<=cnt;++i) a[i].x=-(a[i].x-mod);
sort(a+1,a+cnt+1,tmp);
cdq(1,cnt);//查找右上
for(i=1;i<=tot;++i) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息