向前走莫回头❤

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

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

[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;
}



posted @ 2016-09-11 09:25  lris0-0  阅读(68)  评论(0编辑  收藏  举报
过去的终会化为美满的财富~o( =∩ω∩= )m