题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6681
题意:现在有个矩形的蛋糕,并在蛋糕上建立笛卡尔坐标系,原点在左下角,一个人在蛋糕上切了 k k k刀,每一刀可以看成一条射线,射线起点在 ( x , y ) (x,y) (x,y)向四个方向射出,问所有射线最后将蛋糕切成了多少个部分。数据保证没有射线沿着边界并且没有两条射线在同一条直线上。
解题心得:由于数据已经排除了很多难得处理的数据,这个题就仅仅是离散化后一个树状数组维护就行了。将所有的射线按方向不同分别存放,然后都按照起点 y y y值大小排序,处理向上的射线时,从大到小枚举,如果射向左右的射线起点 y y y坐标大于枚举的向上射线起点 y y y坐标,就按照起点 x x x坐标放在树状数组中,处理向下的射线则按起点 y y y坐标从小到大枚举,方法是相同的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129#include <bits/stdc++.h> using namespace std; const int maxn = 3e5+100; struct Line {//存储射线,0123分别表示上下左右 int x, y, dir; }line[maxn]; struct Line2 {//仅仅存储每条射线的起点坐标 int x, y; bool operator < (const Line2& x) const { return y > x.y; } }; vector <int> ve;//用于离散化 vector <Line2> Down, Up, Left, Right;//按方向存储不同射线 int n, m, k, sum[maxn]; long long ans; void init() { Down.clear(); Up.clear(); Left.clear(); Right.clear(); ve.clear(); ans = 1; memset(sum, 0, sizeof sum); scanf("%d%d%d",&n, &m, &k); for(int i=1;i<=k;i++) { char s[5]; scanf("%d%d%s", &line[i].x, &line[i].y, s); ve.push_back(line[i].x); ve.push_back(line[i].y); //0123分别表示上下左右 if(s[0] == 'U') line[i].dir = 0; if(s[0] == 'D') line[i].dir = 1; if(s[0] == 'L') line[i].dir = 2; if(s[0] == 'R') line[i].dir = 3; } sort(ve.begin(), ve.end()); ve.erase(unique(ve.begin(), ve.end()), ve.end()); for(int i=1;i<=k;i++) { line[i].x = lower_bound(ve.begin(), ve.end(), line[i].x) - ve.begin() + 1; line[i].y = lower_bound(ve.begin(), ve.end(), line[i].y) - ve.begin() + 1; if(line[i].dir == 0) Up.push_back({line[i].x, line[i].y}); if(line[i].dir == 1) Down.push_back({line[i].x, line[i].y}); if(line[i].dir == 2) Left.push_back({line[i].x, line[i].y}); if(line[i].dir == 3) Right.push_back({line[i].x, line[i].y}); } sort(Up.begin(), Up.end()); sort(Down.begin(), Down.end()); sort(Left.begin(), Left.end()); sort(Right.begin(), Right.end()); } int lowbit(int x) { return x&-x; } void add(int pos, int va) { while(pos < maxn) { sum[pos] += va; pos += lowbit(pos); } } int getSum(int pos) { int Sum = 0; while(pos) { Sum += sum[pos]; pos -= lowbit(pos); } return Sum; } void checke_up() {//枚举向上的射线 int IndexL = 0, IndexR = 0; for(int i=0;i<Up.size();i++) { int Y = Up[i].y; while(IndexL < Left.size() && Left[IndexL].y >= Y) { add(1, 1); add(Left[IndexL].x+1, -1); IndexL++; } while(IndexR < Right.size() && Right[IndexR].y >= Y) { add(Right[IndexR].x, 1); IndexR++; } ans += getSum(Up[i].x); } } void checke_down() {//枚举向下的射线 memset(sum, 0, sizeof sum); int IndexL = Left.size()-1, IndexR = Right.size()-1; for(int i=Down.size()-1;i>=0;i--) { int Y = Down[i].y; while(IndexL >= 0 && Left[IndexL].y <= Y) { add(1, 1); add(Left[IndexL].x+1, -1); IndexL--; } while(IndexR >= 0 && Right[IndexR].y <= Y) { add(Right[IndexR].x, 1); IndexR--; } ans += getSum(Down[i].x); } } int main() { // freopen("1.in.txt", "r", stdin); int t; scanf("%d", &t); while(t--) { init(); checke_up(); checke_down(); printf("%lldn", ans); } return 0; }
最后
以上就是粗犷白昼最近收集整理的关于HDU:6681-Rikka with Cake的全部内容,更多相关HDU:6681-Rikka内容请搜索靠谱客的其他文章。
发表评论 取消回复